我对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);
}
}
我不确定哪种方法更适合用于关闭连接:
@Override
protected void finalize() throws Throwable {
conn.close();
super.finalize();
}
或
finally {
conn.close();
}
在按钮ActionListener中尝试捕获块后。
在一些例子中,人们说最后块更好,但是当我有很多方法(4示例动作监听器)时,我会在DB上做一些操作。我应该在所有方法中打开和关闭连接还是只使用finalize方法?
答案 0 :(得分:5)
使用数据库时,需要考虑一些概念:
执行此操作的步骤:
以下是使用HikariCP执行此操作的示例:
定义将使用数据库连接池的数据源:
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;
}
}
在尽可能短的范围内使用连接。
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);
}
}
如果您正在使用Java 7或更高版本,那么请使用try-with-resources(毕竟这是语法糖):
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());
}
}
});
答案 1 :(得分:2)
如果您使用的是Java 7及更高版本,我建议您使用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.
在你的情况下:
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());
}
}
您还应注意,如果要关闭PreparedStatement,则无需关闭ResultSet。 (见this回答)
答案 2 :(得分:1)
关于Java的好处是PreparedStatement
,Connection
和ResultSet
都使用AutoCloseable
。如果要创建一个将一次性关闭所有这些实例的方法:
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
}
}
}
然后,您可以调用此方法并在您创建的任何使用AutoCloseable
但没有固定长度参数的实例中进行折腾。
最好在close()
块中使用finally
调用,因为如果抛出异常,则无论如何都会执行finally
块。否则,您可能会遇到多个连接处于打开状态的问题。
答案 3 :(得分:0)
最终更合适的是总是被称为。记住任何conn不为空的检查
答案 4 :(得分:0)
标准方法是在finally块中关闭它以节省DB资源并避免泄漏。使用具有空闲超时的连接池可以获得最佳结果:http://www.mchange.com/projects/c3p0/index.html。
答案 5 :(得分:0)
我会对所有方法/事务使用try / catch / finally。在关闭它们之前,您应该检查连接,结果集和预准备语句是否为空。对于方法的finally块,这样的东西:
finally {
try {
if (rset != null) {
rset.close();
}
if (st != null) {
st.close();
}
} catch (Exception e) {
// do something
}
}
使用完数据库后,我会用一个方法关闭连接:
public void close() {
if (!isOpen) return;
try {
if (conn != null) {
conn.close();
}
} catch (Exception e) {
// do something
}
isOpen = false;
conn = null;
}
希望它有所帮助: - )