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

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

  1. hibernate 刷新_Hibernate事实:了解刷新操作顺序很重要

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

  2. 电脑桌面计算机打开很慢,电脑桌面刷新反应很慢怎么办?电脑桌面刷新很慢解决方法...

    我们在使用电脑时,有时候为了电脑反应更加快速,在关闭一些程序进程后都会习惯得刷新几次尽快释放内存.有时候我们点击刷新,电脑桌面图标需要很久才反应刷新出来,浪费时间,影响使用体验.出现电脑桌面刷新反应很 ...

  3. 为什么点开桌面计算机那这么慢,电脑桌面刷新反应很慢怎么办?电脑桌面刷新很慢解决方法...

    我们在使用电脑时,有时候为了电脑反应更加快速,在关闭一些程序进程后都会习惯得刷新几次尽快释放内存.有时候我们点击刷新,电脑桌面图标需要很久才反应刷新出来,浪费时间,影响使用体验.出现电脑桌面刷新反应很 ...

  4. 休眠事实:如何“断言” SQL语句计数

    介绍 Hibernate简化了CRUD操作,尤其是在处理实体图时. 但是任何抽象都有其代价,而Hibernate也不例外. 我已经讨论了获取策略和了解Criteria SQL查询的重要性,但是您可以做 ...

  5. java版铁傀儡刷新机制,我的世界:新版村庄的铁傀儡数量都快赶上村民了?刷新效率很高!...

    在沙盒游戏我的世界中,铁傀儡一直以来都是村庄和村民最忠诚的守护者,它们的创作灵感来自天空之城,平时还会给小村民送花,一旦发现其他生物欺负村民就会被它们视为攻击目标,相信有不少的熊孩子玩家曾经都体验过铁 ...

  6. 休眠事实:集成测试策略

    我喜欢集成测试,这是检查Hibernate生成哪些幕后花絮的SQL查询的好方法. 但是集成测试需要运行的数据库服务器,这是您必须要做的第一选择. 1.使用类似生产的本地数据库服务器进行集成测试 对于生 ...

  7. 休眠事实:始终检查Criteria API SQL查询

    Criteria API对于动态构建查询非常有用,但这是我使用它的唯一用例. 每当您有一个带有N个过滤器且可以以任意M个组合到达的UI时,都有一个API动态构造查询是有意义的,因为串联字符串始终是我所 ...

  8. 休眠事实:有利于双向集vs列表

    Hibernate是一个很棒的ORM工具,它极大地简化了开发,但是如果您想正确地使用它,则有很多陷阱. 在大中型项目中,具有双向父子关联非常常见,这使我们能够浏览给定关系的两端. 在控制关联的持久/合 ...

  9. 休眠事实:等于和HashCode

    每个Java对象都继承了equals和hashCode方法,但它们仅对Value对象有用,对面向无状态行为的对象毫无用处. 尽管使用" =="运算符比较引用很简单,但是对于对象相等 ...

最新文章

  1. 什么是接口幂等性?为什么会产生这个问题?如何保证接口幂等性?
  2. Java知识点总结(JavaIO- System类对IO的支持与Scanner类 )
  3. 解决Latex图片或者表格浮动
  4. 网络推广外包专员浅析网络推广外包中网站转化率的发展意义
  5. 审计署计算机培训心得体会,审计署计算机中级培训心得体会
  6. 计算机软件申请专利的困难,对于一个软件系统,在中国现在可以申请专利吗?...
  7. php写进度条原理,php实现进度条原理
  8. C#中扩展StringBuilder支持链式方法
  9. Postfix:邮件系统常见错误代码解释
  10. 拉普拉斯变换公式表_MIT—微分方程笔记20 拉氏变换求解线性常微分方程
  11. Qt_Error QObject: Cannot create children for a parent that is in a different thread. 线程注意!!!
  12. 清华大学计算机系哪个专业就业前景最好,往年清华大学就业前景最好的专业
  13. 如何提高阿里云商标注册的成功率?(经验分享)
  14. 漫步微积分二十五——面积问题
  15. 山西大学量子计算机,山西大学贾晓军课题组:在量子网络的多个节点之间建立和存储确定性量子纠缠...
  16. Ubuntu 使用XCB
  17. 怎样在计算机中找小键盘,笔记本怎么关小键盘【方法步骤】
  18. 单片机测量脉宽c语言程序,利用51系列单片机定时器功能实现测量脉冲宽度
  19. 2048游戏英雄榜java_2048游戏攻略 2048分数排行榜详解
  20. python-CST MWS自动采样

热门文章

  1. IDEA把Springboot打成可执行jar包,内嵌tomcat 这个可以用
  2. 从oracle里面取直,45个非常有用的 Oracle 查询语句小结
  3. matlab eval 不显示,matlab中 eval(command); 运算符无效的问题
  4. 转:json与map互转
  5. Java中synchronized同步块的执行流程
  6. java序列化和反序列化_Java恶意序列化背后的历史和动机
  7. 动态代码生成 静态代码生成_将速度提升到自己的个人代码生成器中
  8. spring内容协商管理_Spring框架中的内容协商
  9. 如何连接oracle xe_为什么应始终将连接池与Oracle XE一起使用
  10. grpc 流式传输_编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中...