java对已分离的对象进行Hibernate不必要的查询

时间:2014-07-03 21:13:59

标签: java mysql sql hibernate jpa

我使用hibernate和c3p0连接池插入,更新和删除许多分离的对象。 问题是hibernate不会批处理语句,而是执行

select @@session.tx_read_only
每个session.persist / insert / update / delete(object)之间的

。分析sql-connection它看起来像这样:

select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only
insert...
select @@session.tx_read_only

选择@@ session.tx_rad_only总是返回" 0" (当然)。使用无状态会话还是有状态会话并不重要。由此产生的表现是不可接受的,并且远非任何期望。

我的Hibernate Konfiguration:

 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:4040/xy?zeroDateTimeBehavior=convertToNull</property>
    <property name="hibernate.connection.username">xy</property>
    <property name="hibernate.connection.password">xy</property>
    <property name="hibernate.connection.autocommit">false</property>
    <property name="hibernate.show_sql">false</property>
    <property name="hibernate.format_sql">false</property>
    <property name="hibernate.use_sql_comments">false</property>
    <property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
    <property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">250</property>
    <property name="hibernate.c3p0.idle_test_period">3000</property>
    <property name="hibernate.jdbc.batch_size">250</property>
    <property name="hibernate.connection.release_mode">auto</property>
    <property name="hibernate.order_inserts">true</property>
    <property name="hibernate.order_updates">true</property>
    <property name="hibernate.cache.use_second_level_cache">false</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="net.sf.ehcache.configurationResourceName">hibernate_ehcache.xml</property>

我正在使用:

<dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>4.3.5.Final</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.31</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.4.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>ejb3-persistence</artifactId>
        <version>1.0.2.GA</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>4.3.4.Final</version>
    </dependency>

我对hibernate几乎没有任何考验,这是一个很好的猜测,我犯了一个很大的错误,所以请随时提出建议。 我切换到休眠,因为ORM功能来自普通的jdbc预处理语句,具有极快的性能。 MYSQL-Server处于良好的配置状态。

EDIT1: 我知道: Unnecessary queries in Hibernate - MySql 我的实体中没有任何事务注释,也没有任何定义的隔离级别

EDIT2: 我将连接池更改为bonecp - 问题仍然存在。似乎显然是一个休眠的配置问题。

EDIT3: 尝试了许多不同的东西,发现可能有一丝暗示: 如果我manualy session.flush()每5个插入(=批量的大小,例如)[试过来自休眠的批处理示例AGAIN], select @@ session.tx_read_only 查询会出现双重 - 每5个查询。因此,我假设 select @@ session.tx_read_only 与刷新有关。有没有办法阻止hibernate刷新每一次插入/更新? 我到目前为止尝试过:session.setFlushMode(FlushMode.COMMIT / NEVER / etc)没有任何行为变化。也许我错误配置了什么...... hibernate触发什么来刷新每个插入?桌上的唯一约束? hibernate验证框架?复杂的对象图?困难的并发?也许是一个锁定问题(Hibernate不确定是否其他人锁定了表并且没有批处理但是如果表是只读的则检查每个插入?)?

我发现没有任何与这种极端(我认为)冲洗bahaviour有关。

3 个答案:

答案 0 :(得分:7)

我们通过在连接字符串中设置useLocalSessionState = true来解决此问题。

以下链接解释了Mysql5.6和java连接器5.1.23发生的ReadOnly相关更改的详细信息。 http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-1-23.html

答案 1 :(得分:1)

您需要在单个事务中包含所有这些CRUD操作,以便所有语句都在同一个数据库连接中执行。

您还可以启用以下Hibernate配置:

<property name="hibernate.order_inserts" value="true"/>
<property name="hibernate.order_updates" value="true"/>
<property name="hibernate.jdbc.batch_size" value="50"/>

这些查询并不意味着您没有批处理。这是一个MySQL thing

某些驱动程序需要特殊的批处理重新排序指令:

<property name="hibernate.connection.url">jdbc:mysql://host:port/db?rewriteBatchedStatements=true</property

答案 2 :(得分:0)

我在配置中发现了这个漏洞。 我不得不从

更改mysql连接字符串
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:4040/xy?zeroDateTimeBehavior=convertToNull</property>

<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:4040/xy?rewriteBatchedStatements=true</property>    
这解决了我的问题。