Метод статического подключения в Java

#java #sql #static #connection

Вопрос:

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

 private static Connection conn()
    {
        
        Connection connection = null;
            
        try {
            
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            connection = (Connection)DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
            

        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
        return connection;
        
    }
 

Затем для получения результатов используется новый метод:

 public void getResult(ArrayList test)
    {
        
        try
        {
            
            Connection conn = conn();
            
            String sql = "select id from test";
            
            PreparedStatement ps = conn.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            
            while(rs.next())
            {
                
               test.add(rs.getInt("id"));
                
            }
            
            conn.close();
            
        } catch (SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
 

Теперь я не знаю, безопасно ли это. Соединение запускается заново каждый раз, когда вызывается метод (?), и я закрываю его. Конечно, объединение пулов соединений было бы полезно для производительности, но безопасно ли это для потоков?

Комментарии:

1. Технически это потокобезопасно, но подвержено утечке соединения в случае возникновения исключения. В conn.close() этом случае он не был бы вызван. Он conn.close() должен быть в блоке finally или в коде, измененном для использования функции try-with-resources, которая будет вызывать его неявно.

2. Означает ли это, что я мог бы использовать его в веб-приложении с finally block, и он все равно был бы потокобезопасным?

3. Извините, теперь я вижу, что вы уже ответили на этот вопрос. Я хочу отметить ваш комментарий как ответ.

4. Я скопировал информацию в ответ и добавил немного больше деталей, чтобы сделать ее достойной ответа. 🙂

Ответ №1:

Технически это потокобезопасно, но подвержено утечке соединения в случае возникновения исключения. В conn.close() этом случае он не был бы вызван. Он conn.close() должен быть в блоке finally или в коде, измененном для использования функции try-with-resources, которая будет вызывать его неявно.

Функция try-with-resources (Java 7 ) позволяет объявлять переменные, реализующие Autocloseable интерфейс в операторе try. Эти переменные затем изящно закрываются в конце try блока.

 try( Connection conn = conn(); ) 
{
  //.... other statements
} catch(SQLException e) {
  //.... exception code
}
 

Ответ №2:

Если вы хотите использовать одно соединение, которое вы можете объявить Connection object as private instance object и всегда check if it is null перед созданием нового соединения.

 private Connection connection = null;
private static Connection conn()
{
    
    if ( connection == null) {
    try {
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        connection = (Connection)DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");

      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException ex) {
        Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
      }

    }
    
    return connection;
}
 

 public void getResult(ArrayList test)
{
    
    try
    {
        Connection conn = conn();
        
        String sql = "select id from test";
        
        PreparedStatement ps = conn.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        
        while(rs.next())
        {
            
           test.add(rs.getInt("id"));
            
        }
        
    } catch (SQLException ex) {
        Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
    }
     finally{
       try {
         conn.close();
         conn = null;
       }
       catch(Exception e)
       {
         //Unable to close connection
       }
     }
    
}