休眠事实:了解刷新操作顺序很重要

Hibernate将开发人员的思维方式从思考SQL转变为思考对象状态转换。 根据Hibernate Docs,实体可能处于以下状态之一:

  • new / transient:实体不与持久性上下文关联,因为它是数据库不知道的新创建的对象。
  • 持久性:实体与持久性上下文相关联(位于第一级缓存中),并且存在一个表示该实体的数据库行。
  • 分离:实体以前与持久性上下文相关联,但是持久性上下文已关闭,或者手动撤消了该实体。
  • 已删除:实体被标记为已删除,并且持久性上下文将在刷新时从数据库中将其删除。

通过调用EntityManager方法来将对象从一种状态移动到另一种状态,例如:

  • 坚持()
  • 合并()
  • 去掉()

级联允许将给定事件从父级传播到子级,还简化了实体关系管理的管理。

在刷新期间,Hibernate会将当前持久性上下文记录的更改转换为SQL查询。

现在,考虑一下以下代码中发生了什么(为简洁起见,将其简化):

@Entity
public class Product {@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "product", orphanRemoval = true)@OrderBy("index")private Set images = new LinkedHashSet();public Set getImages() {return images;}public void addImage(Image image) {images.add(image);image.setProduct(this);}public void removeImage(Image image) {images.remove(image);image.setProduct(null);}
}@Entity
public class Image {@Column(unique = true)private int index;@ManyToOneprivate Product product;public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public Product getProduct() {return product;}public void setProduct(Product product) {this.product = product;}
}final Long productId = transactionTemplate.execute(new TransactionCallback() {@Overridepublic Long doInTransaction(TransactionStatus transactionStatus) {Product product = new Product();Image frontImage = new Image();frontImage.setIndex(0);Image sideImage = new Image();sideImage.setIndex(1);product.addImage(frontImage);product.addImage(sideImage);entityManager.persist(product);return product.getId();}
});try {transactionTemplate.execute(new TransactionCallback() {@Overridepublic Void doInTransaction(TransactionStatus transactionStatus) {Product product = entityManager.find(Product.class, productId);assertEquals(2, product.getImages().size());Iterator imageIterator = product.getImages().iterator();Image frontImage = imageIterator.next();assertEquals(0, frontImage.getIndex());Image sideImage = imageIterator.next();assertEquals(1, sideImage.getIndex());Image backImage = new Image();sideImage.setName("back image");sideImage.setIndex(1);product.removeImage(sideImage);product.addImage(backImage);entityManager.flush();return null;}
});fail("Expected ConstraintViolationException");
} catch (PersistenceException expected) {assertEquals(ConstraintViolationException.class, expected.getCause().getClass());
}

由于存在Image.index唯一约束,因此在刷新期间会收到ConstraintviolationException。

您可能想知道为什么会发生这种情况,因为在添加具有相同索引的backImage之前,我们为sideImage调用remove,并且答案是冲洗操作顺序。

根据Hibernate JavaDocs ,SQL操作顺序为:

  • 插入
  • 更新
  • 集合元素的删除
  • 集合元素的插入
  • 删除

因为我们的图像集合是“ mappedBy”,所以图像将控制关联,因此“ backImage”插入发生在“ sideImage”删除之前。

select product0_.id as id1_5_0_, product0_.name as name2_5_0_ from Product product0_ where product0_.id=?
select images0_.product_id as product_4_5_1_, images0_.id as id1_1_1_, images0_.id as id1_1_0_, images0_.index as index2_1_0_, images0_.name as name3_1_0_, images0_.product_id as product_4_1_0_ from Image images0_ where images0_.product_id=? order by images0_.index
insert into Image (id, index, name, product_id) values (default, ?, ?, ?)
ERROR: integrity constraint violation: unique constraint or index violation; UK_OQBG3YIU5I1E17SL0FEAWT8PE table: IMAGE

要解决此问题,您必须在除去操作之后手动刷新持久性上下文:

transactionTemplate.execute(new TransactionCallback<Void>() {@Overridepublic Void doInTransaction(TransactionStatus transactionStatus) {Product product = entityManager.find(Product.class, productId);assertEquals(2, product.getImages().size());Iterator<Image> imageIterator = product.getImages().iterator();Image frontImage = imageIterator.next();assertEquals(0, frontImage.getIndex());Image sideImage = imageIterator.next();assertEquals(1, sideImage.getIndex());Image backImage = new Image();backImage.setIndex(1);product.removeImage(sideImage);entityManager.flush();product.addImage(backImage);entityManager.flush();return null;}
});

这将输出所需的行为:

select versions0_.image_id as image_id3_1_1_, versions0_.id as id1_8_1_, versions0_.id as id1_8_0_, versions0_.image_id as image_id3_8_0_, versions0_.type as type2_8_0_ from Version versions0_ where versions0_.image_id=? order by versions0_.type
delete from Image where id=?
insert into Image (id, index, name, product_id) values (default, ?, ?, ?)
  • 源代码在这里 。

参考: Hibernate Facts:在Vlad Mihalcea的Blog博客上 ,我们的JCG合作伙伴 Vlad Mihalcea 知道冲洗操作的顺序很重要 。

翻译自: https://www.javacodegeeks.com/2013/11/hibernate-facts-knowing-flush-operations-order-matters.html

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

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

相关文章

[HNOI2012]排队

题目描述 某中学有 n 名男同学&#xff0c;m 名女同学和两名老师要排队参加体检。他们排成一条直线&#xff0c;并且任意两名女同学不能相邻&#xff0c;两名老师也不能相邻&#xff0c;那么一共有多少种排法呢&#xff1f;&#xff08;注意&#xff1a;任意两个人都是不同的&a…

声速的测量的实验原理和应用_声速的测定实验报告心得体会

测量声速的实验报告1。提出问题如何测出声音的速度?2。猜想与假设如果在一定距离内听到声音要多少时间?3。实验步骤步骤应该就是实施实验&#xff0c;第三是实验器材的话&#xff0c;就是要秒表。4。实施实验在一个山谷中&#xff0c;站在距离峭壁680M的地方大叫一声&#xf…

FreeNAS:创建 CIFS 共享(权限)

第一部分&#xff1a;新建账户与指定数据集权限 简单起见&#xff0c;本教程主要介绍带基本身份验证的 CIFS 共享&#xff0c;即只有输入正确的用户名和密码才可以访问共享目录。关于创建匿名共享、多用户权限管理以及域控制器相关内容&#xff0c;我们会另外发布教程专门介绍。…

使用序列化查找对象中的脏字段

假设您正在开发一个将对象自动保存到数据库中的框架。 您需要检测两次保存之间所做的更改&#xff0c;以便仅保存修改过的字段。 如何检测脏场。 最简单的方法是遍历原始数据和当前数据&#xff0c;并分别比较每个字段。 代码如下&#xff1a; public static void getDirtyFie…

js操作table中tr的顺序,实现上移下移一行的效果

总体思路是在table外部加个div&#xff0c;修改div的innerHtml实现改变tr顺序的效果 具体思路是 获取当前要移动tr行的rowIndex&#xff0c;在table中删除掉&#xff0c;然后循环table的rows&#xff0c;到了目标行再直接加进去&#xff0c;最后把整体的html赋值给div完成效果…

oracle日记账单据编号未生成_商管财务数据平台Oracle与共享未付池差异如何核对、解决?...

‍‍近期&#xff0c;总部新上线财务数据平台啦&#xff01;各个系统间的差异异常数据清晰可见&#xff0c;随时可查&#xff0c;今天就和小伙伴们一起分享一下Oracle与共享未付池差异如何核对、解决。首先&#xff0c;将Oracle与共享未付池差异数据导出。由于导出的数据包括本…

python (六)函数

一、函数的形成 需求1&#xff1a;来测试一下‘hello word’ 的长度 # 在没有函数的时候&#xff0c;我们可以用for循环实现 s1 "hello world" length 0 for i in s1:length length1 print(length) 再增加一个需求2&#xff1a;再来测试一下另外一个字符串的长度&…

Java方法中的参数太多,第4部分:重载

期望将过多的参数传递给Java方法的问题之一是&#xff0c;该方法的客户端很难确定它们是否以适当的顺序传递了适当的值。 在以前的文章中&#xff0c;我描述了如何使用自定义类型 &#xff0c; 参数对象和构建器来解决此问题。 解决此问题的另一种方法&#xff08;也是本文的主…

android paint 圆角 绘制_[BOT] 一种android中实现“圆角矩形”的方法

内容简介文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式&#xff0c;四个角可以分别指定为圆角。思路是利用“Xfermode Path”来进行Bitmap的裁剪。背景圆角矩形实现的方法应该很多&#xff0c;网上一大堆。很怀疑为啥安卓的控件不内置这样的属…

解决高度塌陷问题

所谓高度塌陷就是在文档流中&#xff0c;父元素的高度默认是被子元素撑开的&#xff0c;也就是子元素多高&#xff0c;父元素就多高。但是当为子元素设置浮动以后&#xff0c;子元素会完全脱离文档流&#xff0c;此时将会导致子元素无法撑起父元素的高度&#xff0c;导致父元素…

HDU2035 - 人见人爱A^B

求A^B的最后三位数表示的整数。 说明&#xff1a;A^B的含义是“A的B次方” Input 输入数据包含多个测试实例&#xff0c;每个实例占一行&#xff0c;由两个正整数A和B组成&#xff08;1<A,B<10000&#xff09;&#xff0c;如果A0, B0&#xff0c;则表示输入数据的结束&…

Cisco TrustSec(理解)

1、Cisco TrustSec的限制当指定了无效的设备ID时&#xff0c;受保护的访问凭据&#xff08;Protected access credential&#xff0c;PAC&#xff09;设置将失败并保持挂起状态。 即使在清除PAC并配置正确的设备ID和密码后&#xff0c;PAC仍然会失败。作为解决方法&#xff0c;…

Java 8仍然需要LINQ吗? 还是比LINQ更好?

长期以来&#xff0c; LINQ是.NET软件工程生态系统中发生的最好的事情之一。 通过在Visual Studio 2008中引入lambda表达式和monads &#xff0c;它使C&#xff03;语言比Java&#xff08;当时的版本6&#xff09;更先进&#xff0c;并且仍在讨论泛型类型擦除的优缺点。 这项成…

web前端(12)—— 页面布局2

本篇博文&#xff0c;主要就讲定位的问题&#xff0c;也就是页面布局里最重要的&#xff0c;本篇博文不出意外的话&#xff0c;也是css的最后一篇博文了 定位&#xff0c;position属性 定位有三种&#xff1a; 相对定位绝对定位固定定位 相对定位&#xff0c;position&#x…

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

题目链接 \(Description\) 给定一棵树。每次询问给定\(a\sim b,c\sim d\)两个下标区间&#xff0c;从这两个区间中各取一个点&#xff0c;使得这两个点距离最远。输出最远距离。\(n,q\leq10^5\)。 \(Solution\) 一个集合直径的两端点&#xff0c;在被划分为两个集合后一定是两个…

Web应用程序中的Spring JDBC入门

在上一篇文章中&#xff0c;我已经向您展示了如何设置基本的Spring 3 MVC Web应用程序 。 重复使用该项目设置作为模板&#xff0c;我将向您展示如何增强它以与JDBC一起使用。 有了它&#xff0c;您可以存储和检索数据库中的数据。 我们将通过Spring添加一个新的控制器和一个数…

python pyplot中axis_Python Pyplot xaxis未显示在图形上

pyplot未在图形上显示x轴&#xff1a;import pandas as pdimport matplotlib.pyplot as pltdf pd.read_csv(sitka_weather_2014.csv)df[AKST] pd.to_datetime(df.AKST)df[Dates] df[AKST].dt.strftime(%b %d, %Y)df.set_index("Dates", inplace True)# Plot Dataf…

为什么dubbo的调用重试不建议设置成超过1

前面提到过&#xff0c;重试是靠ClusterInvoker来保证的&#xff0c;不同的Cluster在调用失败的时候 做不同处理 比如默认的FailoverClusterInvoke的doInvoke方法里面&#xff1a;int len getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Co…

web前端入门学习(纯干货)

web前端怎么样才能入门&#xff0c;首先我们要从什么是初级web前端工程师说起&#xff1a; 按照我的想法&#xff0c;我把前端工程师分为了入门、初级、中级、高级这四个级别&#xff0c; 入门级别指的是了解什么是前端&#xff08;前端到底是什么其实很多人还是不清楚的&…

用BlockingExecutor限制任务提交

JDK的java.util.concurrent.ThreadPoolExecutor允许您将任务提交到线程池&#xff0c;并使用BlockingQueue来保存提交的任务。 如果您要提交数千个任务&#xff0c;请指定一个“绑定”队列&#xff08;即最大容量的队列&#xff09;&#xff0c;否则JVM可能会耗尽内存。 您可以…