2014-10-09 4 views
1

Мы разрабатываем сайт с помощьюTomcat пул соединений и простаивающие соединения

  • Tomcat 7
  • JDBC
  • PostgreSQL 9,2

У нас были некоторые утечки соединения и думаю, что мы их исправил (база данных перестает отвечать на запросы), но поведение пула соединений по-прежнему кажется неаккуратным, так как у нас есть несколько незанятых соединений, большее, чем maxIdle, заданное в context.xml. Я хотел бы убедиться, что проблема исправлена.

Для целей тестирования, я использую следующий context.xml:

<Resource 
    auth="Container" 
    name="jdbc/postgres" 
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
    type="javax.sql.DataSource" 

    username="admin" 
    password="..." 

    driverClassName="org.postgresql.Driver" 
    url="jdbc:postgresql://127.0.0.1:5432/..." 
    initialSize="1" 
    maxActive="50" 
    minIdle="0" 
    maxIdle="3" 
    maxWait="-1" 
    minEvictableIdleTimeMillis="1000" 
    timeBetweenEvictionRunsMillis="1000" 
    /> 

Если я правильно понимаю, мы должны иметь 1 незанятое соединение при запуске и от 0 до 3 в зависимости от нагрузки, не так ли?

Что происходит: 1 подключение при запуске, до 3 простых соединений при низкой нагрузке и более 3 холостых соединений после высокой нагрузки. Тогда эти связи не закрываются сразу, и мы не знаем, когда/если они будут закрыты (иногда некоторые из них закрыты).

Итак, вопрос: такое поведение нормальное, или нет?

Спасибо за вашу помощь

EDIT: добавлен атрибут завод, не изменил проблему

EDIT 2: с помощью removeAbandoned & removeAbandonedTimeout сделать праздные наставничества закрытия каждый removeAbandonedTimeout. Таким образом, мы, вероятно, все еще имеем некоторые утечки связи. Вот некоторые фрагменты кода, которые мы используем для подключения к базе данных и выполнение запросов:

PostgreSQLConnectionProvider, просто статический класс, чтобы обеспечить соединение:

public class PostgreSQLConnectionProvider { 

    public static Connection getConnection() throws NamingException, SQLException { 

     String dsString = "java:/comp/env/jdbc/postgres"; 
     Context context = new InitialContext(); 
     DataSource ds = (DataSource) context.lookup(dsString); 
     Connection connection = ds.getConnection(); 

     return connection; 
    } 
} 

DAO абстрактный класс :

public abstract class DAO implements java.lang.AutoCloseable { 

    // Private attributes : 
    private Connection _connection; 

    // Constructors : 
    public DAO() { 

     try { _connection = PostgreSQLConnectionProvider.getConnection(); } 
     catch (NamingException | SQLException ex) { 
      Logger.getLogger(DAO.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

    // Getters : 
    public Connection getConnection() { return _connection; } 

    // Closeable : 
    @Override 
    public void close() throws SQLException { 

     if(!_connection.getAutoCommit()) { 

      _connection.rollback(); 
      _connection.setAutoCommit(true); 
     } 

     _connection.close(); 
    } 
} 

UserDAO, небольшой DAO подкласс (у нас есть несколько DAO sublasses запрашивать базу данных):

public class UserDAO extends DAO { 

    public User getUserWithId(int id) throws SQLException { 

     PreparedStatement ps = null; 
     ResultSet rs = null; 

     User user = null; 

     try { 

      String sql = "select * from \"USER\" where id_user = ?;"; 

      ps = getConnection().prepareStatement(sql); 
      ps.setInt(1, id); 

      rs = ps.executeQuery(); 
      rs.next(); 

      String login = rs.getString("login"); 
      String password = rs.getString("password"); 
      String firstName = rs.getString("first_name"); 
      String lastName = rs.getString("last_name"); 
      String email = rs.getString("email"); 

      user = new User(id, login, password, firstName, lastName, email); 
     } 
     finally { 

      if(rs != null) rs.close(); 
      if(ps != null) ps.close(); 
     } 

     return user; 
    } 
} 

Пример использования DAO подкласса:

try(UserDAO dao = new UserDAO()) { 

    try { 

     User user = dao.getUserWithId(52); 
    } 
    catch (SQLException ex) { 

     // Handle exeption during getUserWithId 
    } 
} 
catch (SQLException ex) { 

    // Handle exeption during dao.close() 
} 
+0

Попробуйте использовать пул соединений пула tomcat - он более функциональный и имеет хорошую документацию https://people.apache.org/~fhanik/jdbc-pool/jdbc-pool.html –

+0

Спасибо, но это уже что я делаю (вы можете увидеть параметры, которые я использую в контексте .xml). –

+0

Я не вижу основную часть - атрибут 'factory' и соответствующее имя класса –

ответ

1

Глядя на код, похоже, соединение захватывается для времени жизни DAO, а не времени жизни оператора, что является обычным ожиданием. Как правило, вы должны захватить соединение из пула, так же как вы собираетесь выполнить инструкцию, и вызовите функцию close(), когда вы закончите, чтобы вернуть его в пул.

Кроме того, в вашем предложении finally и rs.close(), и ps.close() могут выдавать исключения, приводящие к отсутствию последнего вызова против подготовленного оператора.

В Java 7 вы также можете использовать оператор try with resources, который закроет как подготовленный оператор, так и соединение для вас. Согласно спецификации, драйвер должен закрыть результат для вас, когда оператор закрыт.

+0

Спасибо за ваш ответ. Да, соединение схвачено за время существования DAO, но DAO закрывается несколькими строками после, я не думаю, что это проблема, не так ли? Вы правы для close(), который может генерировать исключения, я завернул их в try-catch (я предпочитаю сам вызов rs.close() вместо того, чтобы полагаться на реализацию драйвера). Я не могу проверить до следующей недели, я позволю вы знаете, что упаковка close() что-то изменила. –

+0

Если вы создаете экземпляр DAO для каждого вызова getUserWithId(), тогда да, это должно быть хорошо. –

Смежные вопросы