【问题标题】:java Hibernate unnecessary queries on detached objectsjava Hibernate对分离对象的不必要查询
【发布时间】:2014-07-03 21:13:58
【问题描述】:

我正在使用休眠和 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”(当然)。我是使用无状态会话还是有状态会话都没有关系。由此产生的性能是不可接受的,而且与任何预期相去甚远。

我的休眠配置:

 <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 处于良好的配置状态。

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

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

编辑3: 尝试了许多不同的东西,发现可能有一点提示: 如果我每 5 次插入手动设置 session.flush()(=例如批处理的大小)[从休眠中再次尝试批处理示例],则 select @@session.tx_read_only 查询出现双倍 - 每 5 次查询.因此,我假设 select @@session.tx_read_only 与刷新有关。有什么方法可以防止休眠刷新每个插入/更新? 到目前为止,我尝试过: session.setFlushMode(FlushMode.COMMIT/NEVER/etc) 行为没有任何变化。也许我错误地配置了任何东西......休眠触发刷新每个插入是什么?表的唯一约束?休眠验证框架?复杂的对象图?并发难?可能是一个锁定问题(Hibernate 不确定其他人是否锁定了表并且不进行批处理,但如果表是只读的,则检查每个插入?)?

我没有发现任何与这种极端(我假设)潮红行为有关的东西。

【问题讨论】:

    标签: java mysql sql hibernate jpa


    【解决方案1】:

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

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

    【讨论】:

    • 我遇到了同样的问题,这个设置解决了。当我升级到 MySql 5.6 时出现问题,并将 Connector/J 从 5.1.13 升级到 5.1.36,以便能够在 MySql 5.6 中使用新的数据类型。当我切换回 mysql-connector-java-5.1.13-bin.jar 时,每个 INSERT 的额外“SELECT @@session.tx_read_only”消失了。将 useLocalSessionState=true 添加到连接字符串也适用于 mysql-connector-java-5.1.36-bin.jar !因此,这在 JPA(或 Hibernate)中不是问题。感谢您的解决方案!
    • 太棒了。我很高兴这个解决方案对你有用。
    【解决方案2】:

    您需要将所有这些 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
    

    【讨论】:

    • 要正确批处理,您需要一个至少包含当前批处理语句的事务。
    • 更具体地说:我打开一个会话,开始事务,遍历列表并插入对象,提交事务并关闭返回池的会话。插入没有批处理:(
    • 如果您使用身份 ID 生成器,则禁用批处理。
    • 我正在使用增量生成器:@GenericGenerator(name = "xy", strategy = "increment") 感谢您提供这些提示,请继续,以便我检查我的配置!
    • 检查了您的更新,而不是我在我的问题中所说的新信息。
    【解决方案3】:

    我发现我的配置存在缺陷。 我不得不从

    更改mysql-connectionsstring
    <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>    
    

    这解决了我的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 2014-08-08
      • 1970-01-01
      • 2014-10-13
      • 1970-01-01
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多