Java HibernateUtil不返回到c3p0池的连接
在GWT webapp中使用Hibernate时出现一些数据库连接超时问题之后,我们选择使用c3p0作为连接池提供程序。现在我有一个不同的问题:应用程序似乎没有返回到池的连接。 相反,它会在第一次访问数据库时暂停 为了调试这个问题,我遵循了中的建议,因为我的代码也挂起了。因此,我使用了Java HibernateUtil不返回到c3p0池的连接,java,multithreading,hibernate,connection-pooling,c3p0,Java,Multithreading,Hibernate,Connection Pooling,C3p0,在GWT webapp中使用Hibernate时出现一些数据库连接超时问题之后,我们选择使用c3p0作为连接池提供程序。现在我有一个不同的问题:应用程序似乎没有返回到池的连接。 相反,它会在第一次访问数据库时暂停 为了调试这个问题,我遵循了中的建议,因为我的代码也挂起了。因此,我使用了checkoutTimeout来防止客户端无限期地等待,并与debugUnreturnedConnectionStackTraces一起使用debugUnreturnedConnectionStackTraces来
checkoutTimeout
来防止客户端无限期地等待,并与debugUnreturnedConnectionStackTraces
一起使用debugUnreturnedConnectionStackTraces
来获取不返回连接的代码部分的堆栈跟踪。令人惊讶的是,它都是相同的代码(等待连接和不返回连接),并且都在初始化会话工厂的HibernateUtil类中
以下是由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()
因此,MyClass的对象可能在应用程序的不同部分并行实例化,这可能会导致多次调用getSessionFactory()
但据我所知,堆栈跟踪实际上会在类加载(而不是调用getSessionFactory()
)中暂停,我希望这是线程安全的。但是java类加载和相应的静态块实际上是线程安全的吗
以下是我的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>
然后我再次尝试使用较小的maxPoolSize
,现在4个连接也能正常工作。但是3个连接仍然失败。我想问题是由于我做了一个模式更新。显然,hibernate需要更多的连接来进行架构升级,但在我的情况下,至少需要3个连接来进行初始设置
所以我想剩下的唯一问题是,为什么Hibernate需要几个连接来进行设置?为什么一个还不够
java类加载和相应的静态块实际上是线程安全的吗
对。从:
因为Java虚拟机是多线程的,所以
类或接口需要仔细同步,因为
线程可能正在尝试初始化同一个类或接口
同时。还有一种可能性是
类或接口可以作为
初始化该类或接口执行
Java虚拟机负责同步
并使用以下过程进行递归初始化。
请注意,一个类可能由多个类加载器加载,在这种情况下,您会看到静态初始值设定项被调用两次
但据我所知,堆栈跟踪实际上在
类加载
有点。这就是堆栈跟踪()中的clinit
。这实际上是在初始化过程中发生的,而不是在加载过程中
<property name="hibernate.c3p0.timeout">300</property>
300
您确定此值不是以毫秒为单位的吗?300非常短,可以很容易地解释您看到的
debugUnreturnedConnectionStackTraces
。maxPoolSize
-您通过hibernate.c3p0.max\u size
设置的值应该大于1。如果一个操作需要多于maxPoolSize
的连接并且无法完成,那么一个非常小的值会使应用程序很容易冻结。请参阅主要问题下方的评论线程。hibernate.c3p0.timeout
是c3p0.maxIdleTime
(),以秒为单位:。好主意,可惜不是这样。非常感谢您澄清堆栈跟踪的确切含义。首先要做的是设置一个合理的maxPoolSize
(此处为hibernate.c3p0.max_size
)。c3p0是一个连接池,而不是连接单例。1的池将很容易耗尽,如果任何操作同时需要使用多个连接,那么可能会冻结。。设置一个合理的maxPoolSize
可能不足以解决您的问题,在这种情况下,我们将进行讨论。但在你解决之前,花太多时间在这上面是没有意义的。“hibernate.c3p0”是怎么回事?也许那是一次debugUnreturnedConnectionStackTraces
?很抱歉,debugUnreturnedConnectionStackTraces
在复制代码时不知何故丢失了。是的,您是对的缺少的位是debugUnreturnedConnectionStackTraces
,现在在问题中修复了它。关于maxPoolSize
:我觉得在开发过程中使用一个小池在早期发现连接泄漏是一种很好的做法。我可能天真地认为,我正在做的所有事情都只需要一个连接就可以了,因为我没有并行执行任何数据库操作,一次只使用一个hibernate会话。对于一个请求,也不应该有任何可能导致并行连接的多线程处理。@Steve Waldmann I增加了maxPoolSize
,这实际上解决了问题。然而,如上所述,我认为一个连接应该足以满足一个请求。但是显然,Hibernate在初始设置时需要不止一个连接,特别是当它在数据库上执行模式更新时。你知道为什么会这样吗?无论如何,如果您添加“增加maxPoolSize,这是正确的做法”作为答案,我将接受它。;-)一个小水池是好的,但太小是自找麻烦。正如您所遇到的,如果有任何一个操作一次需要超过maxPoolSize
个连接,那么肯定会冻结。我不知道Hibernate的SessionFactory
a的内部结构
<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>
* 2 Connections lead to the same problem
* 4 Connections lead to the same problem
* __8 Connections worked__
<property name="hibernate.c3p0.timeout">300</property>