休眠自动冲洗的黑暗面
介绍
既然我已经描述了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
休眠自动冲洗的黑暗面相关推荐
- hibernate自动配置_Hibernate自动冲洗的黑暗面
hibernate自动配置 介绍 既然我已经描述了JPA和Hibernate刷新策略的基础知识 ,我就可以继续阐明Hibernate的AUTO刷新模式的令人惊讶的行为. 并非所有查询都会触发会话刷新 ...
- android10全局黑暗,传Android 11或加入自动切换全局黑暗模式功能
日前有外媒援引消息人士爆料称,谷歌曾在Android 10系统中带来了全局黑暗模式功能,但自动切换黑暗模式的功能却在Android 10系统的早期测试阶段意外遭砍!而据最新消息显示,Android 1 ...
- 计算机休眠需要重新开机,再确定; 以上的方法能大致解决电脑休眠自动重启的问题...
在使用电脑中途中,若有什么事需要临时离开电脑,大多数人都会选择让电脑休眠,这样不仅节约供电,而且对于文件的安全性也有所保障,所以电脑休眠是很常见的事情.最近就有用户来反应说,经常在电脑休眠的时候,电脑 ...
- 休眠自动提交命令强制MySQL在过多的磁盘I / O中运行
亲爱的大家, 我敢肯定,你们中的许多人都在使用Hibernate和MySQL,我自己在这里和那里都使用它. 通常,编程模型是不错的,但是普通的JDBC可以快很多已经不是什么秘密了. 在这篇文章中,我想 ...
- 黑暗传说单机自动挂机_黑暗传说单机RPGiPhone版|黑暗传说单机RPG苹果版下载_v8.1.0_9ht苹果下载...
黑暗传说单机RPG是一款好玩的角色扮演半放置小游戏.这款游戏是材料党,挂机党,pvg党的胜利,所有升级装备所需的材料都可以通过挂机打怪打出来哦. 游戏介绍 半放置类的角色扮演单机小游戏,大量装备,随机 ...
- 计算机休眠自动开机,win7电脑休眠后会自动开机,睡眠原因?怎么处理?
可能用户没有正确设置关闭休眠功能.什么是休眠:休眠功能是在电脑进入休眠状态时将数据保存到硬盘中,进入休眠状态后,电脑相当于断电了,所以功耗几乎为零!而在休眠状态时不会影响已经保存的数据,当电脑唤醒时, ...
- 人体存在感应雷达应用,智能马桶自动响应,低功耗雷达感应模块
智能马桶是普通马桶升级换代后的产物,与智能科技相结合,利用微电脑控制.智能马桶盖起源于美国,用于医疗和老年保健,后来在韩国和日本得到发展. 各种技术的创新也让洗净马桶不再是一个普通的马桶,自动感应.光 ...
- 拉线自动行走机器人_煤矿机器人重点研发目录来了!
前不久,国家煤矿安监局制定公布了<煤矿机器人重点研发目录>,对掘进.采煤.运煤.安控和救援5类.38种煤矿机器人,分别提出了具体的研发应用要求,希望通过"机器换人"来实 ...
- 通过示例休眠–第2部分(DetachedCriteria)
所以上次我们帮助正义联盟有效地管理了他们的超级英雄. 今天,我们集中讨论"复仇者联盟"将如何使用冬眠的"分离标准"找出每个超级英雄的敌人,以保护他们的超级英雄. ...
最新文章
- 二叉树前序中序后序_leetcode889_go_根据前序和后序遍历构造二叉树
- VTK:Utilities之Box
- spark第十篇:Spark与Kafka整合
- Scrapy 爬取链家租房价格信息
- 《计算智能导论》下载
- 电骡服务器搜索文件排序,电骡搜中文名资源一定要注意的技巧及其他
- 在腾讯开发QQ IM 的工作体验
- GraphPB:Graphical representations of prosody boundary in speech synthesis论文阅读
- 从牛顿-莱布尼兹公式到变限积分求导
- html图片闪烁设置,HTMLCSS基础-图片按钮闪烁解决方案
- RHEL8.x-RedHat-Podman
- matlab制作钟表,利用Matlab制作钟表实例教程
- 面试常见问题之OWASP top10
- 【2】Kali破解家用WI-FI密码 - WPA/WPA2加密
- HarmonyOS荣耀8x,不忘老机型 荣耀9X系列被曝今年将升级HarmonyOS
- 小白量化彩票实战(6)彩票号码中六保五缩水和旋转矩阵
- matlab使用教训
- php 井字棋,怎样用JS做出井字棋游戏
- Java绘图,图像处理
- [附源码]计算机毕业设计springboot体育馆场地预约管理系统
热门文章
- vmware启动多个虚拟机
- WIN10的IE错误代码inet_e_resource_not_found解决办法
- arm linux串口控制led,通信程序设计 - Linux下ARM和单片机的串口通信设计
- URLConnection-URL连接
- java正则表达式 ^expr 和 [^expr] 和 ^[^expr]的比较
- 局域网物理机怎么访问虚拟机
- javaone_代理的JavaOne 2016观察
- oracle aq_通过Java 8流使用Oracle AQ
- 设计模式示例_介体设计模式示例
- mockito入门_Mockito入门