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

hibernate自动配置

介绍

既然我已经描述了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,AUTO刷新模式也可能导致一致性问题。

自动刷新和本机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自动配置

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

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

相关文章

slf4j注解log报错_SpringBoot自定义日志注解,用于数据库记录操作日志,你用过吗?...

大家好,我是程序员7歌!今天我将为大家讲解如何通过自定义注解记录接口访问日志。一般的开发中,有两种方式可以记录日志信息,第一种:把接口日志信息保存到日志文件中,第二种:把接口操作日志保存到…

java applet audion_java applet audion

①希罗尤尔和他的飞翼敢达也有着不少拥趸,让我们期待这位美少年在《敢达决战》中的表现吧。②颜值时代,浏览器皮肤也不能输360浏览器耳目一新的设计,高清精美的壁纸,让你上网时更添一份好心情。软件使用1、支持游戏小号2、优化小程…

markdown 流程图_Markdown 进阶技能:用代码画流程图(编程零基础也适用)

这篇文章主要介绍流程图基础以写代码的方式画流程图相比于使用画图工具拖拽画图,用代码画图有什么好处?首先,这种方式非常轻便,无需安装复杂的画图应用。Typora 等多种 Markdown 编辑器自带有画图扩展(这也是 Markdown…

java jtree_Java JTree

Java JTree1 Java JTree的介绍JTree类用于显示树结构数据或层次结构数据。JTree是一个复杂的组件。它的最顶部有一个“根节点”,它是树中所有节点的父节点。它继承了JComponent类。2 Java JTree的声明我们来看一下javax.swing.JTree类的声明。public class JTree ex…

akka和rabbitmq_Akka Notes –演员记录和测试

akka和rabbitmq在前两部分( 一 , 二 )中,我们简要讨论了Actor以及消息传递的工作方式。 在这一部分中,让我们看一下如何修复并记录我们的TeacherActor 。 回顾 这就是我们上一部分中的Actor的样子: class…

完数c++语言程序_C语言经典100题(19)

1上期答案揭晓首先给大家看看上一篇文章C语言经典100题(18)中第三部分编程题的答案:#includeint main(){ int s0,a,n,t; printf("请输入 a 和 n:\n"); scanf("%d%d",&a,&n); ta; while(n>0) { …

古巴:为生产做准备

“它可以在我的本地机器上运行!” 如今,这听起来像模因,但仍然存在“开发环境与生产环境”的问题。 作为开发人员,您应始终牢记,您的应用程序有一天将在生产环境中开始运行。 在本文中,我们将讨论一些特定于…

hibernate脏数据_Hibernate脏检查的剖析

hibernate脏数据介绍 持久性上下文使实体状态转换入队 ,该实体状态转换在刷新后转换为数据库语句。 对于托管实体,Hibernate可以代表我们自动检测传入的更改并安排SQL UPDATE。 这种机制称为自动脏检查 。 默认的脏检查策略 默认情况下,Hibe…

php组成,php接口有几部分组成?

程序接口,由一套陈述、功能、选项、其它表达程序结构的形式、以及程序师使用的程序或者程序语言提供的数据组成PHP接口(interface)的特点1、接口的方法必须是公开的。2、接口的方法默认是抽象的,所以不在方法名前面加abstract。3、接口可以定义常量&…

java 解析日期格式_日期/时间格式/解析,Java 8样式

java 解析日期格式自Java 几乎 开始以来,Java开发人员就通过java.util.Date类(自JDK 1.0起)和java.util.Calendar类(自JDK 1.1起 )来处理日期和时间。 在这段时间内,成千上万(甚至数百万&#x…

php第三方登录代码,thinkPHP5项目中实现QQ第三方登录功能

本文实例讲述了thinkPHP5项目中实现QQ第三方登录功能。分享给大家供大家参考,具体如下:最近用thinkPHP 5框架做了一个婚纱店的项目,在开发过程中需要用到第三方登录,腾讯官方给的案例是几个文件相互包含实现的,放到tp5…

mac 显示隐藏文件_如何在Mac上显示隐藏文件?苹果mac显示隐藏文件夹方法

与任何操作系统一样,macOS会将重要文件隐藏起来,以防止意外删除它们并因此而损坏系统。但是,在某些情况下,您可能需要在Mac上显示隐藏文件,例如,浏览“ 库”文件夹并清除旧日志,缓存或其他垃圾文…

分布式虚拟跟踪

跟踪提供了对系统的可见性,使开发人员和操作人员可以在运行时观察应用程序。 当系统不断增长并与更多微服务进行交互时,跟踪变得非常有价值。 在这样的环境中,这些痕迹非常棒,可以定位导致性能下降的故障和瓶颈。 在这篇文章中&a…

php 删除数组的空元素,php删除数组空元素的方法_后端开发

php如何实现自动跳转_后端开发php实现自动跳转的方法:1、通过php内置函数“header”,将http响应头中的“Location”设置为要跳转的URL即可;2、可以在javascript代码中将“window.location.href”指向要跳转的URL即可。php删除数组空元素的方法…

map for循环_JavaScript 用 for 循环太 low?你是不是有什么误解

天要吐槽下,我时不时地看到有些文章说“循环语句不好,你应该用 filter,map 和 reduce ”——每次看到有文章鼓吹,所有需要循环的场景一律用这几个函数式方法,我都恨得牙痒痒。没错,这些函数式方法确实有它们…

简单工程验收单表格_中铁超大型工程项目-123个精细化管理手册配套表格附件,超全...

中铁超大型工程项目-123个精细化管理手册配套表格附件,超全!什么是项目精细化?答:工程项目精细化管理是一个系统的管理体系,包含一系列管理制度和办法,除了《工程项目精细化管理办法》这个纲领性文件外&…

判断unsigned long long乘法溢出_信息安全课程17:缓冲区溢出2

在之前所讲述的内容中,都是我们在自己的程序中自行修改的;正常情况下,没有程序员会在自己的代码中这样写——那有没有办法攻击别人正常的程序呢?攻击者怎么样能够影响到不是自己的程序的返回地址呢?以及怎么样通过攻击…

java 保垒机telnet,开源堡垒机系统Teleport

一. teleport简介Teleport是一款简单易用的堡垒机系统,具有小巧、易用的特点,支持 RDP/SSH/SFTP/Telnet 协议的远程连接和审计管理。Teleport由两大部分构成:跳板核心服务WEB操作界面官网地址: https://tp4a.com/ 官网文档: https://docs.…

php背景图片随页面大小改变,css背景图根据屏幕大小自动缩放

css背景图根据屏幕大小自动缩放代码:html,body{margin:0px;padding:0px;}#background { position: fixed;top: 0;left: 0;width: 100%;height: 100%;overflow: hidden;background-color: #211f1f; display:none\8;}#background .bg-photo {position: absolute;top: …

forever不重启 node_运维监控Prometheus,部署安全的node_exporter监控主机

简介prometheus监控系统的时候,是使用pull的方式来获取监控数据,需要被监控端监听对应的端口,prometheus从这些端口服务中拉取对应的数据。node_exporter安全性讨论node_exporter是收集操作系统的指标的一个程序。例如CPU,内存&am…