Зависание соединений SQL: Где я неправильно закрываю соединения? - PullRequest
1 голос
/ 14 июня 2019

Я создаю базовое Java-приложение для загрузки некоторых файлов в базу данных MySQL.Я могу загрузить файлы и заполнить свои таблицы без каких-либо проблем.Однако после разговора с кем-то, кто просмотрел мой код, я, видимо, неправильно закрывал свои соединения и трачу ресурсы.Где я не закрываю связи?Я сделал это неправильно?

Я использую конструкцию try-with-resources в моем классе DbSinger для выполнения подготовленных операторов в моей базе данных, которая должна автоматически закрывать соединение, если реализован интерфейс AutoCloseable, которыйэто в родительском классе Db .Однако метод close () никогда не достигается. DbSinger создается внутри моего main () , а затем запускает его единственный метод populateSingers () с ArrayList из Singer объектов.

Класс соединения

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);}
    }
}

Абстрактный родительский класс

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;
    }
}

Конкретный класс для выполнения запросов к базе данныхдля таблицы певцов

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();
        }
    }

}

Мой код может выполняться, работает нормально и выполняет то, что ему нужно, но я хочу понять, почему и где я не закрываю соединения, и понять,как я могу решить это.Или, по крайней мере, понять, если я подхожу к этому неправильно.

Ответы [ 2 ]

0 голосов
/ 15 июня 2019

В вашем случае вам нужно создать экземпляр класса DBSinger в операторе try-with-resources, чтобы закрыть базовое соединение.

Вместо того, чтобы делать:

DbSinger dbSinger = new DbSinger();

Вам нужно сделать:

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

Таким образом, метод close(), который вы переопределяете в своем классе Db, будет вызываться автоматически.

Кроме того, закройте preparedStatement, созданный вами в методе checkIfPopulated:

try (PreparedStatement ps = getConnection().prepareStatement(query)) {
// Other codes
}
0 голосов
/ 14 июня 2019

Ваш код старый.И вам нужно закрыть вручную.Однако с Java 8 вы можете использовать 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");
 }
...