在我们的 GWT Web 应用程序中使用 Hibernate 出现数据库连接超时的一些问题后,我们选择使用 c3p0 作为连接池提供程序。现在我遇到了一个不同的问题:应用程序似乎没有将连接返回到池。 相反,它会在第一次数据库访问时停止。
为了调试该问题,我遵循了 this question 中的建议。 ,因为我的代码也卡在 waitAvailable 中。因此,我使用 checkoutTimeout
来防止客户端无限期等待,并使用 unreturnedConnectionTimeout
和 debugUnreturnedConnectionStackTraces
来获取未返回的代码部分的堆栈跟踪。返回连接。令人惊讶的是,它们都是相同的代码(都等待连接和不返回连接的代码),并且都在我的 HibernateUtil 类中,该类初始化 session 工厂。
这是由 debugUnreturnedConnectionStackTraces
保存的堆栈跟踪:
java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace.
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:555)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:755)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:682)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at org.hibernate.c3p0.internal.C3P0ConnectionProvider.getConnection(C3P0ConnectionProvider.java:90)
at org.jadira.usertype.spi.shared.AbstractUserTypeHibernateIntegrator.use42Api(AbstractUserTypeHibernateIntegrator.java:80)
at org.jadira.usertype.spi.shared.AbstractUserTypeHibernateIntegrator.integrate(AbstractUserTypeHibernateIntegrator.java:61)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:312)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1859)
at my.package.domain.hibernate.HibernateUtil.<clinit>(HibernateUtil.java:17)
[... snip ...] // user code calling HibernateUtil.getSessionFactory()
awaitAvailable() 超时的类似堆栈跟踪:
com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@ae6163 -- timeout at awaitAvailable()
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1416)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:606)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:526)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:755)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:682)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at org.hibernate.c3p0.internal.C3P0ConnectionProvider.getConnection(C3P0ConnectionProvider.java:90)
at org.jadira.usertype.spi.shared.AbstractUserTypeHibernateIntegrator.use42Api(AbstractUserTypeHibernateIntegrator.java:80)
at org.jadira.usertype.spi.shared.AbstractUserTypeHibernateIntegrator.integrate(AbstractUserTypeHibernateIntegrator.java:61)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:312)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1859)
at my.package.domain.hibernate.HibernateUtil.<clinit>(HibernateUtil.java:17)
[... snip ...] // same client code calling HibernateUtil.getSessionFactory()
对服务器的一个请求就足以导致此问题,因此不存在多个请求。但调用 getSessionFactory 的代码如下所示:
public class MyClass
{
private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// [...] snip
}
因此,MyClass 的对象可能会在应用程序的不同部分并行实例化,这可能会导致多次调用 getSessionFactory()。
但据我了解堆栈跟踪,它实际上在类加载中停止(而不是在对 getSessionFactory()
的调用中),我希望这是线程安全的。但是java类加载和相应的静态 block 实际上是线程安全的吗?
这是我的 HibernateUtil 代码:
public class HibernateUtil
{
private static SessionFactory sessionFactory;
static
{
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(builder.build());
}
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}
它应该这样工作吗?有什么需要改进的地方吗?
为了完整起见,这是我的 hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">
<property name="show_sql">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Connection pool configuration -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">1</property>
<property name="hibernate.c3p0.max_size">1</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">90</property>
<property name="hibernate.c3p0.checkoutTimeout">10000</property><!-- milliseconds -->
<property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces">true</property><!-- do not use in production -->
<property name="hibernate.c3p0.unreturnedConnectionTimeout">60</property>
<!-- Configure automatic session management: https://developer.jboss.org/wiki/Sessionsandtransactions#jive_content_id_Transaction_demarcation_with_plain_JDBC -->
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="hibernate.current_session_context_class">thread</property>
<!-- Configure automatic mapping for Joda Time classes like DateTime and
Instant -->
<property name="jadira.usertype.autoRegisterUserTypes">true</property>
<property name="jadira.usertype.javaZone">UTC</property>
<property name="jadira.usertype.databaseZone">UTC</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- lots of mapped classes -->
</session-factory>
</hibernate-configuration>
编辑:按照@Steve Waldmann的建议,我增加了 maxPoolSize,结果如下:
* 2 Connections lead to the same problem
* 4 Connections lead to the same problem
* __8 Connections worked__
然后我再次尝试使用较小的 maxPoolSize
,现在4 个连接也能正常工作。但3次连接仍然失败。我认为问题是由于我所做的架构更新造成的。显然 hibernate 需要更多连接来进行架构升级,但至少在我的情况下至少需要 3 个连接来进行初始设置。
所以我想剩下的唯一问题是,为什么 Hibernate 需要多个连接来进行设置?为什么一个还不够?
最佳答案
maxPoolSize
— 您通过 hibernate.c3p0.max_size
设置— 应大于 1。如果一个操作需要超过maxPoolSize
,那么非常小的值会使您的应用程序容易卡住。连接并无法完成使用它拥有它们。请参阅主要问题下方的评论线程。
关于java - HibernateUtil 不返回与 c3p0 池的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28838931/