Как я могу предотвратить создание Hibernate + c3p0 + MySql большого количества спящих соединений?

Я использую GWT с Hibernate, c3p0 и MySQL для создания веб-приложения с ограниченной аудиторией (максимум 50 пользователей в день). Во время тестирования я обнаружил, что Hibernate открывает соединение с каждым сеансом, но не закрывает его, независимо от использования метода close().

Моя текущая конфигурация выглядит следующим образом:

hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=
hibernate.connection.username=
hibernate.connection.password=
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.current_session_context_class=thread
hibernate.c3p0.min_size=1
hibernate.c3p0.max_size=1
hibernate.c3p0.timeout=10
hibernate.c3p0.max_statements=50
hibernate.c3p0.idle_test_period=10
hibernate.c3p0.unreturned_connection_timeout=1
hibernate.connection.provider_class=org.hibernate.connection.C3P0ConnectionProvider

При каждом новом подключении к приложению создается новый пул. Например, если я установлю размер пула на 3, 2 подключения к приложению приведут к 6 подключениям, пока приложение не будет закрыто.

Предполагаемое поведение состоит в том, чтобы просто закрывать или повторно использовать соединения после каждой транзакции. Как я могу этого добиться?


person Bradley Stacey    schedule 22.09.2010    source источник


Ответы (3)


Во время тестирования я обнаружил, что Hibernate открывает соединение с каждым сеансом, но не закрывает его, независимо от использования метода close().

При использовании пула соединений вызов Connection#close() физически не закрывает соединение, а возвращает его в пул для повторного использования в будущем. Другими словами, соединение остается открытым, и в этом весь смысл использования пула.


Я вызываю следующее: AnnotationConfiguration().buildSessionFactory().getCurrentSession();

Ну, это проблема. Вы создаете SessionFactory снова и снова (каждый создает свой собственный пул), в то время как вы должны создавать его только один раз на весь срок службы вашего приложения. Если вы не используете какой-либо конкретный фреймворк, это обычно делается в каком-то служебном классе (знаменитый класс HibernateUtil).

В официальном руководстве по Hibernate есть очень простой пример. такого класса. Или см. этот, который немного богаче.

person Pascal Thivent    schedule 22.09.2010
comment
Абсолютно, я это понимаю. Моя проблема в том, что с каждым соответствующим сеансом кажется, что открывается новый пул. Например, если я установлю размер пула 3 и дважды подключусь к приложению, будет 6 открытых подключений, пока приложение не закроется. - person Bradley Stacey; 22.09.2010
comment
@bradleystacey Аааа! Это определенно не то, что я понял из оригинального описания. Как вы управляете SessionFactory? Вы не создаете его для каждого сеанса пользователя, верно? - person Pascal Thivent; 22.09.2010
comment
Я вызываю следующее: AnnotationConfiguration().buildSessionFactory().getCurrentSession(); - person Bradley Stacey; 22.09.2010
comment
Брэдли, это неправильно. Вы должны вызывать buildSessionFactory ОДИН РАЗ для каждого ПРИЛОЖЕНИЯ. Смотрите мой обновленный ответ. - person pakore; 22.09.2010
comment
@bradleystacey Вот в чем проблема. Вы создаете SessionFactory снова и снова, а SessionFactory нужно создавать только один раз. Смотрите мое обновление. - person Pascal Thivent; 22.09.2010

Концепция пула соединений именно такова. У вас есть пул открытых соединений, и когда вам нужно выполнить транзакцию, вы получаете уже открытое соединение. Таким образом, вы экономите много времени на открытии и закрытии соединений. Но вы платите цену за то, чтобы соединения оставались открытыми, когда вы их не используете.

У вас есть дополнительная информация о конфигурации c3p0.

Обновление Очевидно, OP вызывал buildSessionFactory один раз за сеанс. Это должно быть вызвано один раз за время жизни приложения.

Вот служебный класс, который создает sessionFactory Hibernate и предоставляет класс сеанса всем, кто его попросит. Это камберстоун для класса DAO.

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.classic.Session;


public class HibernateUtil {

      private static final SessionFactory sessionFactory;

      static {
          try {
              // Create the SessionFactory from hibernate.cfg.xml
              sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
          } catch (Throwable ex) {
              // Make sure you log the exception, as it might be swallowed
              System.err.println("Initial SessionFactory creation failed." + ex);
              throw new ExceptionInInitializerError(ex);
          }
      }

      public static SessionFactory getSessionFactory() {
          return sessionFactory;
      }

      public static Session getCurrentSession() {
          return sessionFactory.getCurrentSession();
      }

}
person pakore    schedule 22.09.2010
comment
OP использует правильные свойства для настройки пула в hibernate.cfg.xml, см. mchange.com/projects/c3p0/index.html#hibernate-specific - person Pascal Thivent; 22.09.2010
comment
Понятно, я не знал, что такое спящий режим. Я обновил свой ответ. Спасибо. - person pakore; 22.09.2010

Не рекомендуется использовать пул соединений, если вы хотите закрыть соединение после каждой транзакции. Это именно то, чего пулы соединений хотят избежать... Вы должны просто отключить C3PO. Hibernate будет обрабатывать соединение самостоятельно (открывать и закрывать как простое соединение JDBC в каждой транзакции)

person Plínio Pantaleão    schedule 22.09.2010