简体   繁体   English

SQL连接悬空:我在哪里不能正确正确关闭连接?

[英]SQL connections dangling: Where am I not correctly closing up connections correctly?

I am building a basic java application to load some files into a mysql database. 我正在构建一个基本的Java应用程序,以将一些文件加载​​到mysql数据库中。 I am able to load the files up and populate my tables without any problems. 我能够加载文件并填充表格而不会出现任何问题。 However after speaking to someone who reviewed my code, I am apparently not correctly closing my connections and wasting resources. 但是,在与检查了我的代码的人交谈之后,我显然没有正确关闭我的连接并浪费了资源。 Where am I not closing up the connections? 我在哪里不关闭连接? Have I done this incorrectly? 我做错了吗?

I am using the try-with-resources construct within my DbSinger class to execute prepared statements to my database, which should automatically close the connection so long as the AutoCloseable interface is implemented, which it is in the parent class of Db . 我在DbSinger类中使用try-with-resources构造执行对数据库的准备好的语句,只要实现了AutoCloseable接口(位于Db的父类中),该数据库就应自动关闭连接。 The close() method however is never reached. 但是,永远不会达到close()方法。 The DbSinger is instantiated inside my main() and then runs it's single method populateSingers() with an ArrayList of Singer objects. DbSinger在我的main()中实例化,然后使用Singer对象的ArrayList运行它的单个方法populateSingers()

Connection Class 连接等级

public class SQLConnection {
    private static final String servername = "localhost";
    private static final int port = 3306;
    private static final String user = "ng_user";
    private static final String pass = "ng";
    private static final String db = "ng_music";
    private static final String connectionString = "jdbc:mysql://" + servername + ":" + port + "/" + db;

    public Connection provide() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            return DriverManager.getConnection(connectionString, user, pass);

        }
        catch (SQLException | ClassNotFoundException e) {
            throw new SQLConnectionException(e);
        }
    }

    public class SQLConnectionException extends RuntimeException {
        SQLConnectionException(Exception e) {super(e);}
    }
}

Abstract parent class 抽象父类

public abstract class Db implements AutoCloseable{
    private Connection connection;

    Db() {
        SQLConnection sqlC = new SQLConnection();
        this.connection = sqlC.provide();
    }

    @Override
    public synchronized void close() throws SQLException {
        if(connection != null) {
            connection.close();
            connection = null;
            System.out.println("Connection closed");
        }
    }
    Connection getConnection() {
        return connection;

    }
    boolean checkIfPopulated(String query){
        try {
            PreparedStatement ps = getConnection().prepareStatement(query);
            ResultSet rs = ps.executeQuery();
            return !rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return true;
    }
}

Concrete class to execute queries to database for singers table 具体类对歌手表执行对数据库的查询

public class DbSinger extends Db {
    public DbSinger() {
        super();
    }

    public void populateSingers(ArrayList<Singer> singers) {
        String populateSingersQuery = "insert into ng_singers(name, dob, sex) values(?,?,?)";
        if(!checkIfPopulated("select * from ng_singers")){
            System.out.println("Singer Table is already populated");
            return;
        }
        try (PreparedStatement ps = getConnection().prepareStatement(populateSingersQuery)) {
            for (Singer s : singers) {
                ps.setString(1, s.getName());
                ps.setDate(2, java.sql.Date.valueOf(s.getDob()));
                ps.setString(3, s.getSex());
                ps.addBatch();
            }
            ps.executeBatch();
            System.out.println("Singers added to table");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

My code is able to execute is able to run fine and does what it needs to, but I want to understand why and where I am not closing connections, and to understand how I can resolve this. 我的代码能够执行,能够正常运行并完成所需的工作,但是我想了解为什么不关闭连接的原因和位置,以及如何解决此问题。 Or at least understand if I am approaching this wrong. 或者至少了解我是否正在解决这个错误。

Your code is old way. 您的代码是旧的方式。 And you do need close manually. 而且您确实需要手动关闭。 However, with Java 8, you can use try with resource like below, 但是,对于Java 8,您可以try with resource以下try with resource使用try with resource

 try (Connection conn = ds.getConnection();
    Statement stmt = conn.createStatement()) {
    try {
       stmt.execute(dropsql);
   } catch (Exception ignore) {} // ignore if table not dropped
   stmt.execute(createsql);
   stmt.execute(insertsql);
   try (ResultSet rs = stmt.executeQuery(selectsql)) {
     rs.next();
   } catch (Exception e2) {
     e2.printStackTrace();
     return("failed");
   }
 } catch(Exception e) {
   e.printStackTrace();
   return("failed");
 }

In your case, you need to instantiate DBSinger class in try-with-resources statement to close the underlying connection. 对于您的情况,您需要在try-with-resources语句中实例化DBSinger类以关闭基础连接。

Instead of doing: 而不是做:

DbSinger dbSinger = new DbSinger();

You need to do: 您需要做:

try (DbSinger dbSinger = new DbSinger()) {
// Your other code
}

This way the close() method you are overriding in your Db class will be called automatically. 这样,将自动调用您在Db类中覆盖的close()方法。

Also, close the preparedStatement you created in your checkIfPopulated method by: 另外, preparedStatement checkIfPopulated方法关闭在checkIfPopulated方法中创建的checkIfPopulated

try (PreparedStatement ps = getConnection().prepareStatement(query)) {
// Other codes
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM