Hibernate与缓存的连接太多

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate与缓存的连接太多相关的知识,希望对你有一定的参考价值。

我正在使用hibernate来尝试检索缓存的查询。

@Transactional
public interface ProductDAO extends JpaRepository<Product, Long> {
    @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value = "true") })
    Product findByCode(String code);
}

我正在加载测试,我在1000次迭代的大循环中执行此操作。

for (int i = 0; i < 500; i++) {
            URL myURL = new URL("http://localhost:8080/test");
            URLConnection myURLConnection = myURL.openConnection();
            myURLConnection.connect();
            myURLConnection.getContent();
        }

我已经使用showsql进行了检查,我看到只有1个SQL语句是为我第一次点击DB而生成的,之后它被缓存了。

然而,即使没有显示SQL,我仍然会收到以下错误:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Too many connections

我的Hibernate属性:

#hibernate properties
hibernate.dialect = ${hibernate.dialect}
hibernate.show_sql = false
hibernate.hbm2ddl.auto = ${hibernate.hbm2ddl}
hibernate.c3p0.min_size = 10
hibernate.c3p0.max_size = 100
hibernate.c3p0.timeout = 300
hibernate.c3p0.max_statements = 50
hibernate.c3p0.acquire_increment = 5
hibernate.c3p0.idle_test_period = 3000

hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
hibernate.cache.use_query_cache=true

数据库配置:

<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="url" value="${db.url}" />
    <property name="driverClassName" value="${db.driverClassName}" />
    <property name="username" value="${db.username}" />
    <property name="password" value="${db.password}" />
</bean>

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="dataSource" ref="dataSource" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="false" />
            <property name="generateDdl" value="true" />
            <property name="databasePlatform" value="${hibernate.dialect}" />
        </bean>
    </property>

    <property name="jpaProperties" ref="hibernateProperties" />

    <property name="packagesToScan">
        <array>
            <value>com.exammple.model</value>
        </array>
    </property>
</bean>

<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="location" value="classpath:/spring/hibernate.properties" />
</bean>

<bean id="sessionFactory" factory-bean="entityManagerFactory" factory-method="getSessionFactory" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="dataSource" ref="dataSource" />
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<jpa:repositories base-package="com.example.dal" entity-manager-factory-ref="entityManagerFactory"
    transaction-manager-ref="transactionManager" repository-impl-postfix="CustomImpl" />
答案

问题是您没有使用连接池的配置。

您正在配置DriverManagerDataSource,它不是一个合适的连接池。你正在将这个bean注入LocalContainerEntityManagerFactoryBean,这会使你的hibernate.connectionhibernate.c3p0属性无用,它们不会被使用。

解决方案很容易丢弃hibernate.c3p0hibernate.connection属性,并用适当的池实现替换DriverManagerDataSource。我建议HikariCP超过C3P0,但这是个人喜好。

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
    <property name="poolName" value="springHikariCP" />
    <property name="connectionTestQuery" value="SELECT 1" />
    <property name="dataSourceClassName" value="${db.driverClassName}" />
    <property name="dataSourceProperties">
        <props>
            <prop key="url">${db.url}</prop>
            <prop key="user">${db.username}</prop>
            <prop key="password">${jdb.password}</prop>
        </props>
    </property>
</bean>

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <constructor-arg ref="hikariConfig" />
</bean>
另一答案

此问题可能有多个问题:

  1. 您不关闭数据库连接。
  2. 您设置的最大connection pool池大小超过了数据库服务器允许的最大连接数。当客户端数量超过允许的最大连接数时,就会出现这样的异常。

我可以使用FlexyPool来监控连接池的使用情况,并查明连接是否泄漏或者是否长时间租用。

更新

正如M. Deinum已经说过的那样,你没有使用连接池。

您仍然可以使用Hibernate C3P0属性,但您必须从dataSource中删除LocalContainerEntityManagerFactoryBean

<property name="dataSource" ref="dataSource" />

这样Hibernate可以使用hibernate.c3p0属性。

以上是关于Hibernate与缓存的连接太多的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate检索策略与检索方式

三大框架 之 Hibernate生成策略与缓存策略(主键生成策略持久化持久化类划分一级缓存事物管理)

hibernate 查询二级缓存连接池

Hibernate性能优化之EHCache缓存

Hibernate 花费了太多时间并执行了一些神秘的操作。

Hibernate的批量操作