Reputation: 1
I'm little confused about closing connection by jdbc.
package Login;
public class LoginFrame {
private JFrame loginFrame;
Connection conn = null;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
LoginFrame window = new LoginFrame();
window.loginFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public LoginFrame() {
initialize();
conn = DBConnect.connectDB();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
loginFrame = new JFrame();
loginFrame.setResizable(false);
loginFrame.setTitle("XXX");
loginFrame.setBounds(100, 100, 350, 300);
loginFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
loginFrame.getContentPane().setLayout(null);
panel = new JPanel();
panel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Login", TitledBorder.LEADING, TitledBorder.TOP, null, SystemColor.inactiveCaptionText));
panel.setBounds(96, 140, 139, 99);
loginFrame.getContentPane().add(panel);
panel.setLayout(null);
loginField = new JTextField();
loginField.setBounds(47, 16, 86, 20);
panel.add(loginField);
loginField.setColumns(10);
passwordField = new JPasswordField();
passwordField.setBounds(47, 37, 86, 20);
panel.add(passwordField);
JButton loginButton = new JButton("Login");
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
String sql = "select * from employees where login=? and password=?";
try{
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, loginField.getText());
pst.setString(2, passwordField.getText());
ResultSet rs = pst.executeQuery();
int countUsr = 0;
while(rs.next()){
countUsr++;
}
if(countUsr == 1){
loginFrame.dispose();
AdminFrame adminFrame = new AdminFrame();
adminFrame.setVisible(true);
}else if(countUsr > 1){
JOptionPane.showMessageDialog(null, "ERR");
}else{
JOptionPane.showMessageDialog(null, "ERR");
passwordField.setText("");
}
rs.close();
pst.close();
}catch(Exception e){
JOptionPane.showMessageDialog(null, "ERR: "+e.getMessage());
}
}
});
loginButton.setBounds(25, 65, 89, 23);
panel.add(loginButton);
}
}
I'm not sure which metod is better to use to close connection:
@Override
protected void finalize() throws Throwable {
conn.close();
super.finalize();
}
or
finally {
conn.close();
}
after a try catch block in button ActionListener.
In some examples people say finally block is better but what when I have many methods(4example Action Listeners) and in every of them I do some operations on DB. Should I open and close connection in all methods or just use finalize method?
Upvotes: 0
Views: 2989
Reputation: 11
I would use a try/catch/finally for all of the methods/transactions. And you should check if the connection, result set and prepared statements are not null before closing them. Something like this for the finally block of a method:
finally {
try {
if (rset != null) {
rset.close();
}
if (st != null) {
st.close();
}
} catch (Exception e) {
// do something
}
}
When you are finished using the database, I would close the connection with a method:
public void close() {
if (!isOpen) return;
try {
if (conn != null) {
conn.close();
}
} catch (Exception e) {
// do something
}
isOpen = false;
conn = null;
}
Hope it helps :-)
Upvotes: 0
Reputation: 85789
When working with databases, there are some concepts to take into account:
Steps to do this:
Here's an example to do this using HikariCP:
Define the data source that will use the database connection pool:
public final class DataSourceFactory {
private static final Logger LOG = LoggerFactory.getLogger(DataSourceFactory.class);
private static DataSource mySQLDataSource;
private DataSourceFactory() { }
private static DataSource getDataSource(String configurationProperties) {
Properties conf = new Properties();
try {
conf.load(DataSourceFactory.class.getClassLoader().getResourceAsStream(configurationProperties));
} catch (IOException e) {
LOG.error("Can't locate database configuration", e);
}
HikariConfig config = new HikariConfig(conf);
HikariDataSource dataSource = new HikariDataSource(config);
return dataSource;
}
public static DataSource getMySQLDataSource() {
LOG.debug("Retrieving data source for MySQL");
if (mySQLDataSource == null) {
synchronized(DataSourceFactory.class) {
if (mySQLDataSource == null) {
LOG.debug("Creating data source for MySQL");
mySQLDataSource = getDataSource("mysql-connection.properties");
}
}
}
return mySQLDataSource;
}
}
Use the connection in the shortest possible scope.
public class LoginFrame {
private JFrame loginFrame;
//remove the Connection from here, this is not the shortest possible scope
//Connection conn = null;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
LoginFrame window = new LoginFrame();
window.loginFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public LoginFrame() {
initialize();
conn = DBConnect.connectDB();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
//...
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//This is the shortest possible scope for the connection
//Declare it here and use it
Connection conn = DataSourceFactory.getMySQLDataSource().getConnection();
String sql = "select * from employees where login=? and password=?";
try{
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, loginField.getText());
pst.setString(2, passwordField.getText());
ResultSet rs = pst.executeQuery();
int countUsr = 0;
while(rs.next()){
countUsr++;
}
if(countUsr == 1){
loginFrame.dispose();
AdminFrame adminFrame = new AdminFrame();
adminFrame.setVisible(true);
}else if(countUsr > 1){
JOptionPane.showMessageDialog(null, "ERR");
}else{
JOptionPane.showMessageDialog(null, "ERR");
passwordField.setText("");
}
} catch(Exception e) {
//ALWAYS log the exception, don't just show a message
e.printStackTrace();
JOptionPane.showMessageDialog(null, "ERR: "+e.getMessage());
} finally {
try {
rs.close();
pst.close();
con.close();
} catch (SQLException silent) {
//do nothing
}
}
}
});
loginButton.setBounds(25, 65, 89, 23);
panel.add(loginButton);
}
}
If you're working with Java 7 or superior, then use try-with-resources (which is syntactic sugar, after all):
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//This is the shortest possible scope for the connection
//Declare it here and use it
Connection conn = ;
String sql = "select * from employees where login=? and password=?";
try(Connection conn = DataSourceFactory.getMySQLDataSource().getConnection();
PreparedStatement pst = conn.prepareStatement(sql);) {
pst.setString(1, loginField.getText());
pst.setString(2, passwordField.getText());
try (ResultSet rs = pst.executeQuery();) {
int countUsr = 0;
while(rs.next()){
countUsr++;
}
if(countUsr == 1){
loginFrame.dispose();
AdminFrame adminFrame = new AdminFrame();
adminFrame.setVisible(true);
} else if(countUsr > 1){
JOptionPane.showMessageDialog(null, "ERR");
} else {
JOptionPane.showMessageDialog(null, "ERR");
passwordField.setText("");
}
}
} catch(Exception e) {
//ALWAYS log the exception, don't just show a message
e.printStackTrace();
JOptionPane.showMessageDialog(null, "ERR: "+e.getMessage());
}
}
});
Upvotes: 5
Reputation: 4168
The nice thing about Java is all of PreparedStatement
, Connection
, and ResultSet
use AutoCloseable
. If you want to create a method that will close all of these instances in one shot:
public static void close(AutoCloseable... closeables) {
for (AutoCloseable c : closeables) {
try {
if (c != null) {
c.close();
}
} catch (Exception ex) {
//do something, Logger or or your own message
}
}
}
You can then call this method and toss in any instances you have created that use AutoCloseable
with no fixed length of parameters.
It is best to use close()
calls in a finally
block because if an Exception is thrown, the finally
block will execute anyway. Otherwise you may run into issues with multiple connections being left open.
Upvotes: 1
Reputation: 544
The standard way is to close it in the finally block to save DB resources and avoid leakage. The best results can be obtained using connection pooling with idle timeout: http://www.mchange.com/projects/c3p0/index.html.
Upvotes: 0
Reputation: 1967
If you are using Java 7 and above, I would recommend using try with resources.
The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.
In your case:
try (PreparedStatement pst = conn.prepareStatement(sql))//use try with resources
{
pst.setString(1, loginField.getText());
pst.setString(2, passwordField.getText());
ResultSet rs = pst.executeQuery();
int countUsr = 0;
while(rs.next()){
countUsr++;
}
if(countUsr == 1){
loginFrame.dispose();
AdminFrame adminFrame = new AdminFrame();
adminFrame.setVisible(true);
}else if(countUsr > 1){
JOptionPane.showMessageDialog(null, "ERR");
}else{
JOptionPane.showMessageDialog(null, "ERR");
passwordField.setText("");
}
//removed rst closing, no need to close if your PreparedStatement is being closed.
//No need to explicitly close our PreparedStatement since we are using try with resources
}catch(Exception e){
JOptionPane.showMessageDialog(null, "ERR: "+e.getMessage());
}
}
You should also note that you don't need to close your ResultSet if you are closing your PreparedStatement. (See this answer)
Upvotes: 2
Reputation: 3727
The finally is more appropriate is always called. Remember any check that conn is not null
Upvotes: 0