介绍

既然我已经描述了JPA和Hibernate刷新策略的基础知识 ,我就可以继续阐明Hibernate的AUTO刷新模式的令人惊讶的行为。

并非所有查询都会触发会话刷新

许多人会认为Hibernate 总是在执行任何查询之前先刷新Session。 虽然这可能是一种更直观的方法,并且可能更接近JPA的AUTO FlushModeType ,但是Hibernate尝试对其进行优化。 如果当前执行的查询不会命中未决的SQL INSERT / UPDATE / DELETE语句,则不严格要求刷新。

如参考文档中所述,AUTO刷新策略有时可能在执行查询之前同步当前持久性上下文。 如果框架作者选择将其命名为FlushMode.SOMETIMES,那将更加直观。

JPQL / HQL和SQL

与许多其他ORM解决方案一样,Hibernate提供了一种非常基于SQL-92语法的有限实体查询语言( JPQL / HQL )。

当前数据库方言将实体查询语言转换为SQL,因此它必须在不同的数据库产品中提供相同的功能。 由于大多数数据库系统都是SQL-92投诉,因此实体查询语言是最常见的数据库查询语法的抽象。

虽然您可以在许多用例(选择实体,甚至是投影)中使用实体查询语言,但有时其有限功能与高级查询请求不匹配。 每当我们想要利用某些特定的查询技术时,例如:

  • 视窗功能
  • 数据透视表
  • 常用表表达式

我们别无选择,只能运行本机SQL查询。

Hibernate是一个持久性框架。 Hibernate从未打算取代SQL。 如果某些查询在本机查询中可以更好地表达,那么在数据库可移植性上牺牲应用程序性能是不值得的。

自动冲洗和HQL / JPQL

首先,我们将测试将要执行HQL查询时AUTO刷新模式的行为。 为此,我们定义了以下不相关的实体:

该测试将执行以下操作:

  • 一个人将被坚持。
  • 选择用户不应触发刷新。
  • 查询人员时,AUTO刷新应触发实体状态转换同步(应在执行选择查询之前执行人员INSERT)。
Product product = new Product();
session.persist(product);
assertEquals(0L,  session.createQuery("select count(id) from User").uniqueResult());
assertEquals(product.getId(), session.createQuery("select p.id from Product p").uniqueResult());

提供以下SQL输出:

[main]: o.h.e.i.AbstractSaveEventListener - Generated identifier: f76f61e2-f3e3-4ea4-8f44-82e9804ceed0, using strategy: org.hibernate.id.UUIDGenerator
Query:{[select count(user0_.id) as col_0_0_ from user user0_][]}
Query:{[insert into product (color, id) values (?, ?)][12,f76f61e2-f3e3-4ea4-8f44-82e9804ceed0]}
Query:{[select product0_.id as col_0_0_ from product product0_][]}

如您所见,用户选择尚未触发会话刷新。 这是因为Hibernate会根据挂起的表语句检查当前查询空间。 如果当前正在执行的查询与未刷新的表语句不重叠,则可以安全地忽略刷新。

HQL甚至可以在以下情况下检测到产品冲洗:

  • 子选择

    session.persist(product);
    assertEquals(0L,  session.createQuery("select count(*) " +"from User u " +"where u.favoriteColor in (select distinct(p.color) from Product p)").uniqueResult());

    导致正确的冲洗调用:

    Query:{[insert into product (color, id) values (?, ?)][Blue,2d9d1b4f-eaee-45f1-a480-120eb66da9e8]}
    Query:{[select count(*) as col_0_0_ from user user0_ where user0_.favoriteColor in (select distinct product1_.color from product product1_)][]}
  • 或theta风格的联接
    session.persist(product);
    assertEquals(0L,  session.createQuery("select count(*) " +"from User u, Product p " +"where u.favoriteColor = p.color").uniqueResult());

    触发预期的冲洗:

    Query:{[insert into product (color, id) values (?, ?)][Blue,4af0b843-da3f-4b38-aa42-1e590db186a9]}
    Query:{[select count(*) as col_0_0_ from user user0_ cross join product product1_ where user0_.favoriteColor=product1_.color][]}

它起作用的原因是因为实体查询已被解析并转换为SQL查询。 Hibernate无法引用不存在的表,因此它始终知道HQL / JPQL查询将命中的数据库表。

因此,Hibernate仅知道我们在HQL查询中显式引用的那些表。 如果当前待处理的DML语句暗示数据库触发器或数据库级级联,则Hibernate将不会意识到这些。 因此,即使对于HQL,“自动”刷新模式也可能导致一致性问题。

自动刷新和本机SQL查询

当涉及本地SQL查询时,事情变得越来越复杂。 Hibernate无法解析SQL查询,因为它仅支持有限的数据库查询语法。 许多数据库系统提供了超越Hibernate Entity Query功能的专有功能。

使用本机SQL查询查询Person表不会触发刷新,从而导致不一致问题:

Product product = new Product();
session.persist(product);
assertNull(session.createSQLQuery("select id from product").uniqueResult());
DEBUG [main]: o.h.e.i.AbstractSaveEventListener - Generated identifier: 718b84d8-9270-48f3-86ff-0b8da7f9af7c, using strategy: org.hibernate.id.UUIDGenerator
Query:{[select id from product][]}
Query:{[insert into product (color, id) values (?, ?)][12,718b84d8-9270-48f3-86ff-0b8da7f9af7c]}

新保留的产品仅在事务提交期间插入,因为本机SQL查询未触发刷新。 这是主要的一致性问题,许多开发人员很难调试甚至无法预见。 这是始终检查自动生成的SQL语句的另一个原因。

即使对于命名的本机查询,也会观察到相同的行为:

@NamedNativeQueries(@NamedNativeQuery(name = "product_ids", query = "select id from product")
)
assertNull(session.getNamedQuery("product_ids").uniqueResult());

因此,即使SQL查询已预先加载,Hibernate也不会提取关联的查询空间以使其与未决的DML语句匹配。

否决当前的冲洗策略

即使当前会话定义了默认的刷新策略,您也可以始终在查询基础上覆盖它。

查询刷新模式

ALWAYS模式将在执行任何查询(HQL或SQL)之前刷新持久性上下文。 这次,Hibernate没有应用任何优化,所有待处理的实体状态转换都将与当前数据库事务同步。

assertEquals(product.getId(), session.createSQLQuery("select id from product").setFlushMode(FlushMode.ALWAYS).uniqueResult());

指示Hibernate应该同步哪些表

您还可以在当前正在执行的SQL查询上添加同步规则。 然后,Hibernate将知道在执行查询之前需要同步哪些数据库表。 这对于二级缓存也很有用。

assertEquals(product.getId(), session.createSQLQuery("select id from product").addSynchronizedEntityClass(Product.class).uniqueResult());

结论

自动刷新模式非常棘手,并且在查询基础上解决一致性问题是维护人员的噩梦。 如果决定添加数据库触发器,则必须检查所有Hibernate查询,以确保它们最终不会针对过时的数据运行。

我的建议是使用ALWAYS刷新模式,即使Hibernate作者警告我们:

这种策略几乎总是不必要且效率低下的。

不一致是一些偶尔过早冲洗的问题。 当混合DML操作和查询可能会导致不必要的刷新时,这种情况很难缓解。 在会话事务期间,最好在事务开始时(没有待处理的实体状态转换要同步时)和事务结束时(无论如何将刷新当前持久性上下文)执行查询。

应将实体状态转换操作推向事务的结尾,以尝试避免将它们与查询操作交错(因此防止过早的刷新触发器)。

翻译自: https://www.javacodegeeks.com/2014/08/the-dark-side-of-hibernate-auto-flush.html

休眠自动冲洗的黑暗面相关推荐

  1. hibernate自动配置_Hibernate自动冲洗的黑暗面

    hibernate自动配置 介绍 既然我已经描述了JPA和Hibernate刷新策略的基础知识 ,我就可以继续阐明Hibernate的AUTO刷新模式的令人惊讶的行为. 并非所有查询都会触发会话刷新 ...

  2. android10全局黑暗,传Android 11或加入自动切换全局黑暗模式功能

    日前有外媒援引消息人士爆料称,谷歌曾在Android 10系统中带来了全局黑暗模式功能,但自动切换黑暗模式的功能却在Android 10系统的早期测试阶段意外遭砍!而据最新消息显示,Android 1 ...

  3. 计算机休眠需要重新开机,再确定; 以上的方法能大致解决电脑休眠自动重启的问题...

    在使用电脑中途中,若有什么事需要临时离开电脑,大多数人都会选择让电脑休眠,这样不仅节约供电,而且对于文件的安全性也有所保障,所以电脑休眠是很常见的事情.最近就有用户来反应说,经常在电脑休眠的时候,电脑 ...

  4. 休眠自动提交命令强制MySQL在过多的磁盘I / O中运行

    亲爱的大家, 我敢肯定,你们中的许多人都在使用Hibernate和MySQL,我自己在这里和那里都使用它. 通常,编程模型是不错的,但是普通的JDBC可以快很多已经不是什么秘密了. 在这篇文章中,我想 ...

  5. 黑暗传说单机自动挂机_黑暗传说单机RPGiPhone版|黑暗传说单机RPG苹果版下载_v8.1.0_9ht苹果下载...

    黑暗传说单机RPG是一款好玩的角色扮演半放置小游戏.这款游戏是材料党,挂机党,pvg党的胜利,所有升级装备所需的材料都可以通过挂机打怪打出来哦. 游戏介绍 半放置类的角色扮演单机小游戏,大量装备,随机 ...

  6. 计算机休眠自动开机,win7电脑休眠后会自动开机,睡眠原因?怎么处理?

    可能用户没有正确设置关闭休眠功能.什么是休眠:休眠功能是在电脑进入休眠状态时将数据保存到硬盘中,进入休眠状态后,电脑相当于断电了,所以功耗几乎为零!而在休眠状态时不会影响已经保存的数据,当电脑唤醒时, ...

  7. 人体存在感应雷达应用,智能马桶自动响应,低功耗雷达感应模块

    智能马桶是普通马桶升级换代后的产物,与智能科技相结合,利用微电脑控制.智能马桶盖起源于美国,用于医疗和老年保健,后来在韩国和日本得到发展. 各种技术的创新也让洗净马桶不再是一个普通的马桶,自动感应.光 ...

  8. 拉线自动行走机器人_煤矿机器人重点研发目录来了!

    前不久,国家煤矿安监局制定公布了<煤矿机器人重点研发目录>,对掘进.采煤.运煤.安控和救援5类.38种煤矿机器人,分别提出了具体的研发应用要求,希望通过"机器换人"来实 ...

  9. 通过示例休眠–第2部分(DetachedCriteria)

    所以上次我们帮助正义联盟有效地管理了他们的超级英雄. 今天,我们集中讨论"复仇者联盟"将如何使用冬眠的"分离标准"找出每个超级英雄的敌人,以保护他们的超级英雄. ...

最新文章

  1. 二叉树前序中序后序_leetcode889_go_根据前序和后序遍历构造二叉树
  2. VTK:Utilities之Box
  3. spark第十篇:Spark与Kafka整合
  4. Scrapy 爬取链家租房价格信息
  5. 《计算智能导论》下载
  6. 电骡服务器搜索文件排序,电骡搜中文名资源一定要注意的技巧及其他
  7. 在腾讯开发QQ IM 的工作体验
  8. GraphPB:Graphical representations of prosody boundary in speech synthesis论文阅读
  9. 从牛顿-莱布尼兹公式到变限积分求导
  10. html图片闪烁设置,HTMLCSS基础-图片按钮闪烁解决方案
  11. RHEL8.x-RedHat-Podman
  12. matlab制作钟表,利用Matlab制作钟表实例教程
  13. 面试常见问题之OWASP top10
  14. 【2】Kali破解家用WI-FI密码 - WPA/WPA2加密
  15. HarmonyOS荣耀8x,不忘老机型 荣耀9X系列被曝今年将升级HarmonyOS
  16. 小白量化彩票实战(6)彩票号码中六保五缩水和旋转矩阵
  17. matlab使用教训
  18. php 井字棋,怎样用JS做出井字棋游戏
  19. Java绘图,图像处理
  20. [附源码]计算机毕业设计springboot体育馆场地预约管理系统

热门文章

  1. vmware启动多个虚拟机
  2. WIN10的IE错误代码inet_e_resource_not_found解决办法
  3. arm linux串口控制led,通信程序设计 - Linux下ARM和单片机的串口通信设计
  4. URLConnection-URL连接
  5. java正则表达式 ^expr 和 [^expr] 和 ^[^expr]的比较
  6. 局域网物理机怎么访问虚拟机
  7. javaone_代理的JavaOne 2016观察
  8. oracle aq_通过Java 8流使用Oracle AQ
  9. 设计模式示例_介体设计模式示例
  10. mockito入门_Mockito入门