【问题标题】:Hibernate : C3p0 pool configuration slowing down entire server.休眠:C3p0 池配置降低了整个服务器的速度。
【发布时间】:2018-09-19 18:00:29
【问题描述】:

我正在开发一个 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>

根上下文.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 并不能真正处理大量数据,这会导致服务器速度慢和出现您描述的错误。当你遇到这样的麻烦时,要么你需要尝试优化你的查询,要么你需要切换到原生 SQL 查询
  • @DamCx :有多个查询,因为需要从 DB 获取大量信息。所有这些查询都会定期使用,没有任何问题。
  • 我无法对配置发表评论,但您是否尝试过将 C3PO 换成 Hikari 之类的东西? github.com/brettwooldridge/HikariCP
  • 你是如何确定是 C3P0 的罪魁祸首?
  • 使用top 不太适合分析Java 进程。虽然您可能会观察到没有任何实际的内存泄漏,但您对内存使用模式一无所知。

标签: java spring postgresql hibernate c3p0


【解决方案1】:

对于初学者,您不使用 C3P0 仅仅是因为您已将 org.apache.commons.dbcp.BasicDataSource 配置为 DataSource 并将其注入您的 LocalSessionFactoryBean。这基本上使所有hibernate.c3p0 设置无用,因为它们将被忽略。

接下来,您在处理大量数据时遇到问题,我非常怀疑问题出在您的 DataSource 或连接池上,而是您处理实体的方式以及您如何配置 Hibernate。

为了加快批处理速度,您希望将每 x 条记录刷新到数据库并清除一级缓存。你为什么要这样做,你可能想知道。这与 Hibernate 的工作方式有关,当您持久化一个实体时,Hibernate 所做的事情会将其添加到一级缓存(在 JPA 的情况下为SessionEntityManager)。每次您将项目添加到一级缓存时,它都会对一级缓存中的所有实体进行脏检查,以确定是否需要刷新某些内容。现在这对于前几个实体来说会很快,但会变得越来越慢。

让我们为批量大小为 50 的东西配置和编码。

首先,您希望将休眠配置为具有适当的批量大小,并且您希望订购插入和更新语句。如果您这样做,您可以受益于 JDBC 现在可以进行批量更新(即一个插入或更新语句来修改 50 条记录,而不是 50 条单个插入/更新语句)。

休眠配置

<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 是一个很好的资源(带有基准测试等),了解每个设置的作用、添加或删除性能以及如何正确配置。

【讨论】:

  • 首先,我正在添加 HikariCP。一旦完成。我将修改较大的代码以使用批处理。最后,如果这没有帮助,将编写本机 SQL 查询而不是休眠。使用 HikariCP 时出现错误,其中 Transactionmanager 抱怨 bean 必须是 sessionFactory 类型。你能检查一下这个配置吗:pastebin.com/xE0HSggC。谢谢。
  • 您应该替换 DataSource 而不是 LocalSessionFactoryBean。仅更改数据源不会有太大作用,真正的缺陷在于您处理数据的方式。
  • 好的。将更改数据源。修改处理代码完成后,我将提出一个新问题。
  • 这很好用,方法仍然很慢,所以我在 CodeReview 中发布了一个问题。你可以看看:codereview.stackexchange.com/questions/191768/… 谢谢。 :-)
  • 每次您将项目添加到一级缓存时,它都会对一级缓存中的所有实体进行脏检查以确定是否需要刷新某些内容为什么需要脏检查?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 2013-12-29
  • 2020-07-01
  • 2016-09-03
  • 2016-05-13
相关资源
最近更新 更多