Пул соединений Hibernate, Spring и c3p0 приводит к тому, что JBoss открывает слишком много соединений с базой данных.

У меня странная проблема с моим приложением, работающим на JBoss 6.1, которое использует Hibernate и Spring. Я также использую c3p0 для пула соединений.

У меня есть источник данных, определенный в JBoss. Источником данных является C3P0PooledDataSource. Обратите внимание, что maxpoolsize равен 20, и исходный размер пула также равен 20.

<mbean code="com.mchange.v2.c3p0.jboss.C3P0PooledDataSource"
      name="jboss.jca:service=DataSourceBinding,name=db/MED_POOLED">

  <attribute name="JndiName">java:db/MED_POOLED</attribute>
  <attribute name="JdbcUrl">jdbc:oracle:thin:@dbhost:1521:SID</attribute>
  <attribute name="DriverClass">oracle.jdbc.driver.OracleDriver</attribute>
  <attribute name="User">xxx</attribute>
  <attribute name="Password">xxx</attribute>
  <attribute name="AutomaticTestTable">POOL_TEST</attribute>          
  <attribute name="CheckoutTimeout">30000</attribute>      
  <attribute name="Description">Pooled Datasource for med</attribute>
  <attribute name="IdleConnectionTestPeriod">180</attribute>     
  <attribute name="InitialPoolSize">20</attribute>  
  <attribute name="MaxPoolSize">20</attribute>   
  <attribute name="MinPoolSize">20</attribute>    
  <attribute name="TestConnectionOnCheckin">true</attribute>       
  <attribute name="MaxIdleTime">3600</attribute>
  <depends>jboss:service=Naming</depends>
</mbean>

В моем файле конфигурации spring источник данных извлекается с использованием имени jndi:

<bean id="defaultDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName"><value>db/MED_POOLED</value></property>
</bean>

а затем используется для создания LocalSessionFactoryBean

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="defaultDataSource"/>
    <property name="namingStrategy" ref="namingStrategy"/>
    <property name="configLocations">
        <list>
        <value>classpath:hibernate.cfg.xml</value>
        <value>classpath:jbpm.hibernate.cfg.xml</value>
        </list>
    </property>
    <property name="mappingDirectoryLocations">
        <list><value>WEB-INF/classes</value></list>
    </property>
</bean>

В hibernate.cfg.xml источник данных не определен, поэтому следует использовать свойство dataSource в org.springframework.orm.hibernate3.LocalSessionFactoryBean.

Когда я запускаю свой сервер приложений, происходит что-то странное (по крайней мере, странное для меня):

  • JBoss запускается, вижу в логе эту строчку

    [com.mchange.v2.c3p0.jboss.C3P0PooledDataSource] Связал C3P0 PooledDataSource с именем 'java:db/MED_POOLED'. Начиная...

и если я проверю базу данных, 20 сеансов присутствуют.

  • Когда создается LocalSessionFactoryBean, внезапно появляется 40 подключений к базе данных, но в моей конфигурации источника данных я указал создание максимум 20 подключений.

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

Вы знаете, что происходит? Что-то не так с моей конфигурацией?

Я использую JBoss 6.1, последнюю доступную версию c3p0 (0.9.5), Spring 3.0.3.RELEASE и Hibernate 3.5.3-Final.


person Luca Casarotti    schedule 01.07.2014    source источник
comment
Включите ведение журнала DEBUG для пакета org.springframework и посмотрите, выделяется ли в журналах что-нибудь необычное.   -  person Andrei Stefan    schedule 01.07.2014
comment
добавьте дополнительные файлы cfg.   -  person M. Deinum    schedule 01.07.2014


Ответы (1)


Существует два возможных способа, при которых количество подключений может вдвое превышать ожидаемый размер пула.

  1. Возможно, вы каким-то образом инициализируете два источника данных c3p0;
  2. Вы можете получить Connections для двух разных аутентификаций, позвонив dataSource.getConnection( user, password )

Самый простой способ проверить эти две возможности — через JMX: если C3P0Registry MBean показывает два разных источника PooledDataSource, это ваша проблема. В противном случае найдите свойство numUserPools внутри вашего источника данных: их два?

Я бы сначала рассмотрел эти возможности.

[Если у вас нет доступа к JMX, вы можете увидеть, были ли инициализированы несколько источников данных, просматривая записи журнала на уровне INFO из регистратора с именем com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource, записи, которые начинаются с "Инициализация пула c3p0...", а затем отображать конфигурацию инициализируемого пула.]

Другая возможность заключается в том, что по какой-то причине ваше приложение подвергается горячему повторному развертыванию, но поскольку старый экземпляр приложения удален, ваш источник данных c3p0 не был закрыт. Это будет сложнее отладить и привести к причудливому поведению в целом, если классы c3p0 загружаются несколькими отдельными загрузчиками классов. (Я недостаточно знаю о том, реализует ли JBoss горячее повторное развертывание и каким образом, чтобы знать, может ли это быть проблемой.) Один из способов избежать такого рода проблем — убедиться, что jar-файлы c3p0 доступны в уровень сервера приложений, не являющийся дочерним для какого-либо конкретного приложения, а затем установите для параметра конфигурации c3p0 [0.9.5] contextClassLoaderSource значение library, см. http://www.mchange.com/projects/c3p0/#contextClassLoaderSource

person Steve Waldman    schedule 01.07.2014
comment
Я думаю, проблема в том, что классы c3p0 загружаются из разных загрузчиков классов: у меня есть файлы c3p0, развернутые как в общих библиотеках JBoss, так и в моей библиотеке приложений. К сожалению, если я удалю jar-файлы c3p0 из WEB-INF/lib моего приложения, я получу исключение NoClassDefFoundException для прокси-класса. - person Luca Casarotti; 01.07.2014
comment
Это исключение, которое я получаю, когда удаляю c3p0 из WEB-INF/lib. Ошибка создания bean-компонента с именем «defaultDataSource»: сбой постобработки объекта FactoryBean; вложенным исключением является org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: предупреждение не может определить модификаторы отсутствующего типа com.sun.proxy.$Proxy265 - person Luca Casarotti; 01.07.2014
comment
Я понятия не имею, о чем это. все же попробуйте установить contextClassLoaderSource c3p0 в библиотеку. возможно, вам просто нужны классы для преобразований времени развертывания, но классы будут загружены из общих библиотек сервера приложений. - person Steve Waldman; 01.07.2014