Hibernate、Spring 和 c3p0 连接池导致 JBoss 打开过多的数据库连接

Posted

技术标签:

【中文标题】Hibernate、Spring 和 c3p0 连接池导致 JBoss 打开过多的数据库连接【英文标题】:Hibernate, Spring and c3p0 connection pooling cause JBoss to opens too many connections to database 【发布时间】:2014-08-21 20:43:15 【问题描述】:

我的应用程序有一个奇怪的问题,它在使用 Hibernate 和 Spring 的 JBoss 6.1 上运行。我也在使用 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中没有定义数据源,所以应该使用org.springframework.orm.hibernate3.LocalSessionFactoryBean的dataSource属性。

当我启动我的应用程序服务器时,发生了一些奇怪的事情(至少对我来说很奇怪):

JBoss 启动,我在日志中看到这一行

[com.mchange.v2.c3p0.jboss.C3P0PooledDataSource] 将 C3P0 PooledDataSource 绑定到名称“java:db/MED_POOLED”。开始...

如果我检查数据库,则存在 20 个会话。

创建 LocalSessionFactoryBean 时,突然在 Db 上出现 40 个连接,但在我的数据源配置中,我指定最多创建 20 个连接。

我认为,以某种方式,在创建 LocalSessionFactoryBean 时数据源会重新初始化,但我不明白为什么,当 JBoss 启动时,我的连接数正好是我想要的两倍。

你知道发生了什么吗?我的配置有问题吗?

我正在使用 JBoss 6.1、c3p0 (0.9.5) 的最新可用版本、Spring 3.0.3.RELEASE 和 Hibernate 3.5.3-Final

【问题讨论】:

org.springframework 包启用调试日志记录,看看日志中是否有任何异常。 添加额外的 cfg 文件。 【参考方案1】:

连接数可能是您预期的池大小的两倍。

    您可能正在以某种方式初始化两个 c3p0 数据源; 您可能通过调用dataSource.getConnection( user, password ) 来获取两个不同身份验证下的连接

检查这两种可能性的最简单方法是通过 JMX:如果 C3P0Registry MBean 显示两个不同的 PooledDataSources,那么您就有问题了。否则,在 DataSource 中查找属性 numUserPools:是两个吗?

我会先检查这些可能性。

[如果您无权访问 JMX,您可以通过从名为 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 的记录器中查找 INFO 级别的日志条目来查看多个数据源是否被初始化,条目以“正在初始化 c3p0 池...”开头然后显示正在初始化的池的配置。]

另一种可能性是,由于某种原因,您的应用程序正在热重新部署,但由于应用程序的旧实例被拆除,您的 c3p0 数据源尚未关闭。如果 c3p0 的类由多个不同的 ClassLoader 加载,这将更难调试并且通常会导致古怪的行为。 (我不太了解 JBoss 是否/如何实现热重新部署,不知道这是否可能是一个问题。)避免此类问题的一种方法是确保 c3p0 的 jar 文件在应用服务器级别,不附属于任何特定应用,然后将 c3p0 [0.9.5] 配置参数contextClassLoaderSource 设置为library,参见http://www.mchange.com/projects/c3p0/#contextClassLoaderSource

【讨论】:

我认为问题在于 c3p0 类是从不同的类加载器加载的:我在 JBoss 共享库和我的应用程序库中都部署了 c3p0 jar。不幸的是,如果我从我的应用程序的 WEB-INF/lib 中删除 c3p0 jar,我会在代理类上得到 NoClassDefFoundException 这是我从 WEB-INF/lib 中删除 c3p0 时遇到的异常 创建名为“defaultDataSource”的 bean 时出错:FactoryBean 对象的后处理失败;嵌套异常是 org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException:警告无法确定缺少类型 com.sun.proxy.$Proxy265 的修饰符 我不知道那是什么。不过,请尝试将 c3p0 的 contextClassLoaderSource 设置为库。也许您只需要那里的类来进行部署时间转换,但是类将从应用服务器共享库中加载。

以上是关于Hibernate、Spring 和 c3p0 连接池导致 JBoss 打开过多的数据库连接的主要内容,如果未能解决你的问题,请参考以下文章

Spring c3p0连接池通过Hibernate配置

Hibernate c3p0 连接池不会超时空闲连接

Spring的jdbcTemplate 与原始jdbc 整合c3p0的DBUtils 及Hibernate 对比

spring02

手动加入SSH支持使用c3p0

使用 c3p0 时出现 MySQL Hibernate 连接问题