休眠:C3p0 池配置减慢了整个服务器。
Hibernate : C3p0 pool configuration slowing down entire server.
我正在开发一个 Spring-MVC 应用程序,我们在其中使用 Hibernate 和 c3p0 进行数据库事务和连接池。大多数时候它工作得很好,没有问题。但在某些情况下,我必须在当前事务中复制大量对象和文件。发生这种情况时,整个服务器都会变慢,最后我开始得到 could not rollback exception
。我的 c3p0 设置有什么问题吗?谢谢。
pom.xml :
<!--- Hibernate dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.3.9.Final</version>
</dependency>
root-context.xml :
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url"
value="jdbc:postgresql://localhost:PORT/DB_NAME"/>
<beans:property name="username" value="USERNAME"/>
<beans:property name="password" value="PASSWORD"/>
<beans:property name="removeAbandoned" value="true"/>
<beans:property name="removeAbandonedTimeout" value="20"/>
<beans:property name="defaultAutoCommit" value="false"/>
</beans:bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="packagesToScan" value="com.ourapp.spring.model"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<!--<beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>-->
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="cache.use_second_level_cache">true</beans:prop>
<beans:prop key="cache.use_query_cache">true</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
<beans:prop key="show_sql">false</beans:prop>
<beans:prop key="hibernate.c3p0.min_size">1</beans:prop>
<beans:prop key="hibernate.c3p0.max_size">750</beans:prop>
<beans:prop key="hibernate.c3p0.acquire_increment">1</beans:prop>
<beans:prop key="hibernate.c3p0.idle_test_period">1000</beans:prop>
<beans:prop key="hibernate.c3p0.max_statements">150</beans:prop>
<beans:prop key="hibernate.c3p0.timeout">1200</beans:prop>
<beans:prop key="hibernate.connection.release_mode">auto</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
谢谢。
对于初学者,您使用 C3P0 并不是因为您已将 org.apache.commons.dbcp.BasicDataSource
配置为 DataSource
并将其注入您的 LocalSessionFactoryBean
。这基本上使所有 hibernate.c3p0
设置无用,因为它们将被忽略。
接下来您在处理大量数据时遇到问题,我非常怀疑问题出在您的 DataSource
或连接池上,而是您处理实体的方式以及您配置 Hibernate 的方式。
为了加快批处理速度,您希望将每 x 条记录刷新到数据库并清除一级缓存。您可能想知道为什么要这样做。它与 Hibernate 的工作方式有关,当你持久化一个实体时,Hibernate 会把它添加到一级缓存(在 JPA 的情况下是 Session
或 EntityManager
)。每次将项目添加到一级缓存时,它都会对一级缓存中的所有实体进行脏检查,以确定是否需要刷新某些内容。现在这对于前几个实体来说很快,但会变得越来越慢。
让我们为 50 的批量配置和编码。
首先,您希望将 hibernate 配置为具有适当的批处理大小,并且您希望对插入和更新语句进行排序。如果您这样做,您可以受益于 JDBC 现在可以执行批量更新(即一个插入或更新语句修改 50 条记录而不是 50 个单个 insert/update 语句)这一事实。
休眠配置
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="packagesToScan" value="com.ourapp.spring.model"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<!--<beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>-->
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="hibernate.cache.use_second_level_cache">true</beans:prop>
<beans:prop key="hibernate.cache.use_query_cache">true</beans:prop>
<beans:prop key="hibernate.jdbc.batch_size">50</beans:prop>
<beans:prop key="hibernate.order_inserts">true</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
<!-- If you use versioned entities set this to true as well -->
<beans:prop key="hibernate.jdbc.batch_versioned_data">true<beans:prop>
</beans:props>
</beans:property>
</beans:bean>
代码修改
public void yourLargeDataSetProcessingMethod() {
Session session = sessionFactory.getCurrentSession();
int i = 0;
for (YourItem item : List<YourItem> items) {
i++:
// Here will be processing / creation
if (i % 50 == 0) {
session.flush();
session.clear();
}
}
session.flush();
session.clear();
}
这可能会加速您的处理和数据库锁定。
最后一点,我建议使用 HikariCP 作为连接池,而不是 Commons DBCP 或 C3P0。它非常小,非常快并且得到积极维护(而 C3P0 已经休眠了很长一段时间)。
Here 是一个很好的资源(带有基准测试等),介绍了每个设置的作用、明智地添加或删除性能以及如何正确配置。
我正在开发一个 Spring-MVC 应用程序,我们在其中使用 Hibernate 和 c3p0 进行数据库事务和连接池。大多数时候它工作得很好,没有问题。但在某些情况下,我必须在当前事务中复制大量对象和文件。发生这种情况时,整个服务器都会变慢,最后我开始得到 could not rollback exception
。我的 c3p0 设置有什么问题吗?谢谢。
pom.xml :
<!--- Hibernate dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.3.9.Final</version>
</dependency>
root-context.xml :
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url"
value="jdbc:postgresql://localhost:PORT/DB_NAME"/>
<beans:property name="username" value="USERNAME"/>
<beans:property name="password" value="PASSWORD"/>
<beans:property name="removeAbandoned" value="true"/>
<beans:property name="removeAbandonedTimeout" value="20"/>
<beans:property name="defaultAutoCommit" value="false"/>
</beans:bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="packagesToScan" value="com.ourapp.spring.model"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<!--<beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>-->
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="cache.use_second_level_cache">true</beans:prop>
<beans:prop key="cache.use_query_cache">true</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
<beans:prop key="show_sql">false</beans:prop>
<beans:prop key="hibernate.c3p0.min_size">1</beans:prop>
<beans:prop key="hibernate.c3p0.max_size">750</beans:prop>
<beans:prop key="hibernate.c3p0.acquire_increment">1</beans:prop>
<beans:prop key="hibernate.c3p0.idle_test_period">1000</beans:prop>
<beans:prop key="hibernate.c3p0.max_statements">150</beans:prop>
<beans:prop key="hibernate.c3p0.timeout">1200</beans:prop>
<beans:prop key="hibernate.connection.release_mode">auto</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
谢谢。
对于初学者,您使用 C3P0 并不是因为您已将 org.apache.commons.dbcp.BasicDataSource
配置为 DataSource
并将其注入您的 LocalSessionFactoryBean
。这基本上使所有 hibernate.c3p0
设置无用,因为它们将被忽略。
接下来您在处理大量数据时遇到问题,我非常怀疑问题出在您的 DataSource
或连接池上,而是您处理实体的方式以及您配置 Hibernate 的方式。
为了加快批处理速度,您希望将每 x 条记录刷新到数据库并清除一级缓存。您可能想知道为什么要这样做。它与 Hibernate 的工作方式有关,当你持久化一个实体时,Hibernate 会把它添加到一级缓存(在 JPA 的情况下是 Session
或 EntityManager
)。每次将项目添加到一级缓存时,它都会对一级缓存中的所有实体进行脏检查,以确定是否需要刷新某些内容。现在这对于前几个实体来说很快,但会变得越来越慢。
让我们为 50 的批量配置和编码。
首先,您希望将 hibernate 配置为具有适当的批处理大小,并且您希望对插入和更新语句进行排序。如果您这样做,您可以受益于 JDBC 现在可以执行批量更新(即一个插入或更新语句修改 50 条记录而不是 50 个单个 insert/update 语句)这一事实。
休眠配置
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="packagesToScan" value="com.ourapp.spring.model"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<!--<beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>-->
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="hibernate.cache.use_second_level_cache">true</beans:prop>
<beans:prop key="hibernate.cache.use_query_cache">true</beans:prop>
<beans:prop key="hibernate.jdbc.batch_size">50</beans:prop>
<beans:prop key="hibernate.order_inserts">true</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
<!-- If you use versioned entities set this to true as well -->
<beans:prop key="hibernate.jdbc.batch_versioned_data">true<beans:prop>
</beans:props>
</beans:property>
</beans:bean>
代码修改
public void yourLargeDataSetProcessingMethod() {
Session session = sessionFactory.getCurrentSession();
int i = 0;
for (YourItem item : List<YourItem> items) {
i++:
// Here will be processing / creation
if (i % 50 == 0) {
session.flush();
session.clear();
}
}
session.flush();
session.clear();
}
这可能会加速您的处理和数据库锁定。
最后一点,我建议使用 HikariCP 作为连接池,而不是 Commons DBCP 或 C3P0。它非常小,非常快并且得到积极维护(而 C3P0 已经休眠了很长一段时间)。
Here 是一个很好的资源(带有基准测试等),介绍了每个设置的作用、明智地添加或删除性能以及如何正确配置。