休眠自动冲洗的黑暗面

介绍

既然我已经描述了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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

洛谷P1636学画画

传送 这个题我们需要一个大胆的想法(虽然AC后看了题解知道这是个定理) (求证明qwq) 如果一个图有2或0个奇点,它就一定可以一笔画出,如果不是2或0个奇点,那答案就是奇点数/2 (私认为因…

理解正则

正则的应用场景很多,匹配过滤有价值的内容,所以用好正则有事半功倍的效果正则就是用有限的符号,表达无限的序列正则的一般语法就是两条斜线中间的就是正则主体,可以有许多字符表示转义字符 \是转义字符,简单字符表示自…

vue项目中z-index不起作用(将vue实例挂在到window上面)

问题描述:由于原有项目(传统项目)中嵌入新的vue组件,dialog弹出框的z-index:999999;任然不起作用; 解决办法:将vue实例挂载到window 解决代码如下: 入口文件index.js中 i…

【算法】称骨算命法

称骨算命法是唐代著名的星象预测家袁天罡称骨的预测方法。这种方法同四柱算命一样,能确定一个人一生的吉凶祸福、荣辱盛衰,准确率很高,又便于掌握和运用。 一个人出生的年、月、日、时各有定数,年、月、日、时的重量都有具体规定。…

IDE:5个最喜欢的NetBeans功能

愉快的发展……。 NetBeans具有许多有趣的功能 ,这些功能使开发非常容易,只需很少的步骤,并且可以在非常快速地将产品推向市场的情况下提供高产的环境 。 将我的谈话仅限于五个功能非常困难,而此IDE具有大量有趣的功能。 但是在…

flask总结之session,websocket,上下文管理

1.关于session flask是带有session的,它加密后存储在用户浏览器的cookie中,可以通过app.seesion_interface源码查看 from flask import Flask,sessionapp Flask(__name__)app.secret_key aptx4869 # 必须要指定这个参数app.route(/login)def login():…

Hbase 和 RDBMS的区别

一 Hbase是个什么东西? 首先我们来看看两个概念,面向行存储和面向列存储。面向行存储,我相信大伙儿应该都清楚,我们熟悉的RDBMS就是此种类型的,面向行存储的数据库主要适合于事务性要求严格场合,或者说面向…

css设置背景透明度

设置背景透明用: background-color: rgba(0, 0, 0, 0.4);虽然opacity:0.5;也可以设置背景透明,但是会影响整体;推荐使用rgba设置背景透明,只会在当前的内容内起作用转载于:https://www.cnblogs.com/phermis/p/11395227.html

Hibernate延时加载

首先说明Hibernate3延迟加载只对load,get,find一些内值方法有用,对hql等写sql的无效。延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象…

深入了解Oracle IDM审核

在处理敏感信息的任何产品中, 报告都是至关重要的功能。 同样适用于身份和访问管理工具。 Oracle IDM的审核模块是其OOTB报告功能的基础。 让我们快速看一下审核引擎以及它如何促进OIM中的报告功能。 这里展示的用例很简单– 在OIM中更改为用户记录。 从审核的角度…

c#---ref参数

员工基本工资为5000元,奖金方法500元,调用该方法之后为什么工资还是5000元? static void Main(string[] args){double salary 5000;jiangJin(salary);Console.WriteLine(salary);Console.ReadKey();}public static void jiangJin(double sal…

django批量form表单处理

1.应用说明 一般在表单信息录入中,如果存在许多重复提交的信息,我们就需要进行批量处理,比如学生信息的批量录入。 这里一种方式就是使用xlrd模块处理,把学生信息录入到系统内 另外一种方式就是采用我们from组件中提供的formset来…

手写弹出框,设置遮罩,布局设计。

传统的设计弹出框和遮罩 <template> <div> <div class"这里是内容"> <div class"这里是遮罩"></div> </div> </div> </template> 转载于:https://www.cnblogs.com/phermis/p/11395395.html

【转】一步一步教你远程调用EJB

一步一步教你远程调用EJB http://www.diybl.com/course/1_web/webjs/20071226/94785.htmlwww.diybl.com 时间&#xff1a;2007-12-26 作者:佚名 编辑:本站 点击&#xff1a; 686 [评论]前期准备&#xff1a;弄清楚weblogic&#xff08;或jboss&#xff09;、tomcat、JBluder…

ADF:弹出窗口,对话框和输入组件

在本文中&#xff0c;当我们有一个af&#xff1a;popup包含af&#xff1a;dialog并在其中包含输入组件时&#xff0c;我想着重介绍一个非常常见的用例。 在实现此用例时&#xff0c;需要注意一些陷阱。 让我们考虑一个简单的示例&#xff1a; <af:popup id"p1" …

关于codeforces加载慢

昨天cdx报名cf&#xff0c;打开网页10多分钟才交了、、、。 今天问了wxy&#xff0c;百度了一下&#xff0c;以前也搜过&#xff0c;然后就忘记了。 今天记一下。 1.右键单击开始按钮&#xff0c;打开资源管理器&#xff0c;在资源管理器的地址栏中填写“%SystemRoot%\System3…

ORM 开发环境之利器:MVC 中间件 FreeSql.AdminLTE

前言 这是一篇纯技术干货的分享文章&#xff0c;FreeSql 已经基本完成 .NETCore 最方便的 ORM 使命&#xff0c;我们正在筹备生态的建立&#xff0c;比如 ABP 中如何使用 FreeSql 的实现&#xff0c;需要各种各样的扩展包&#xff0c;好多好多工作量。有没有大神愿意无偿参与做…

Hadoop Ecosystem解决方案---数据仓库

个人总结的一套基于hadoop的海量数据挖掘的开源解决方案.BI系统:Pentahopentaho是开源的BI系统中做得算顶尖的了.提供的核心功能如下:报表功能: 可视化(client, web)的报表设计. 分析功能: 可以生成分析视图&#xff0c;作数据作动态分析. Dashboard功能: 可以定制动态图…

django中间件及中间件实现的登录验证

1.定义 一个用来处理Django的请求和响应的框架级别的钩子&#xff08;函数&#xff09;&#xff0c;相对比较轻量级&#xff0c;并且在全局上改变django的输入与输出&#xff08;使用需谨慎&#xff0c;否则影响性能&#xff09; 直白的说中间件就是帮助我们在视图函数执行之前…

默认方法:Java 8的无名英雄

几周前&#xff0c;我写了一个博客&#xff0c;说开发人员学习新语言是因为它们很酷。 我仍然坚持这个主张&#xff0c;因为关于Java 8的事情真的很酷。 毫无疑问&#xff0c;该节目的明星是添加了Lambdas以及将函数提升为一等变量&#xff0c;而我目前最喜欢的是默认方法。 这…