休眠事实:了解刷新操作顺序很重要
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, ?, ?, ?)
- 源代码在这里 。
翻译自: https://www.javacodegeeks.com/2013/11/hibernate-facts-knowing-flush-operations-order-matters.html
休眠事实:了解刷新操作顺序很重要相关推荐
- hibernate 刷新_Hibernate事实:了解刷新操作顺序很重要
hibernate 刷新 Hibernate将开发人员的思维方式从思考SQL转变为思考对象状态转换. 根据Hibernate Docs,实体可能处于以下状态之一: new / transient:实体 ...
- 电脑桌面计算机打开很慢,电脑桌面刷新反应很慢怎么办?电脑桌面刷新很慢解决方法...
我们在使用电脑时,有时候为了电脑反应更加快速,在关闭一些程序进程后都会习惯得刷新几次尽快释放内存.有时候我们点击刷新,电脑桌面图标需要很久才反应刷新出来,浪费时间,影响使用体验.出现电脑桌面刷新反应很 ...
- 为什么点开桌面计算机那这么慢,电脑桌面刷新反应很慢怎么办?电脑桌面刷新很慢解决方法...
我们在使用电脑时,有时候为了电脑反应更加快速,在关闭一些程序进程后都会习惯得刷新几次尽快释放内存.有时候我们点击刷新,电脑桌面图标需要很久才反应刷新出来,浪费时间,影响使用体验.出现电脑桌面刷新反应很 ...
- 休眠事实:如何“断言” SQL语句计数
介绍 Hibernate简化了CRUD操作,尤其是在处理实体图时. 但是任何抽象都有其代价,而Hibernate也不例外. 我已经讨论了获取策略和了解Criteria SQL查询的重要性,但是您可以做 ...
- java版铁傀儡刷新机制,我的世界:新版村庄的铁傀儡数量都快赶上村民了?刷新效率很高!...
在沙盒游戏我的世界中,铁傀儡一直以来都是村庄和村民最忠诚的守护者,它们的创作灵感来自天空之城,平时还会给小村民送花,一旦发现其他生物欺负村民就会被它们视为攻击目标,相信有不少的熊孩子玩家曾经都体验过铁 ...
- 休眠事实:集成测试策略
我喜欢集成测试,这是检查Hibernate生成哪些幕后花絮的SQL查询的好方法. 但是集成测试需要运行的数据库服务器,这是您必须要做的第一选择. 1.使用类似生产的本地数据库服务器进行集成测试 对于生 ...
- 休眠事实:始终检查Criteria API SQL查询
Criteria API对于动态构建查询非常有用,但这是我使用它的唯一用例. 每当您有一个带有N个过滤器且可以以任意M个组合到达的UI时,都有一个API动态构造查询是有意义的,因为串联字符串始终是我所 ...
- 休眠事实:有利于双向集vs列表
Hibernate是一个很棒的ORM工具,它极大地简化了开发,但是如果您想正确地使用它,则有很多陷阱. 在大中型项目中,具有双向父子关联非常常见,这使我们能够浏览给定关系的两端. 在控制关联的持久/合 ...
- 休眠事实:等于和HashCode
每个Java对象都继承了equals和hashCode方法,但它们仅对Value对象有用,对面向无状态行为的对象毫无用处. 尽管使用" =="运算符比较引用很简单,但是对于对象相等 ...
最新文章
- 什么是接口幂等性?为什么会产生这个问题?如何保证接口幂等性?
- Java知识点总结(JavaIO- System类对IO的支持与Scanner类 )
- 解决Latex图片或者表格浮动
- 网络推广外包专员浅析网络推广外包中网站转化率的发展意义
- 审计署计算机培训心得体会,审计署计算机中级培训心得体会
- 计算机软件申请专利的困难,对于一个软件系统,在中国现在可以申请专利吗?...
- php写进度条原理,php实现进度条原理
- C#中扩展StringBuilder支持链式方法
- Postfix:邮件系统常见错误代码解释
- 拉普拉斯变换公式表_MIT—微分方程笔记20 拉氏变换求解线性常微分方程
- Qt_Error QObject: Cannot create children for a parent that is in a different thread. 线程注意!!!
- 清华大学计算机系哪个专业就业前景最好,往年清华大学就业前景最好的专业
- 如何提高阿里云商标注册的成功率?(经验分享)
- 漫步微积分二十五——面积问题
- 山西大学量子计算机,山西大学贾晓军课题组:在量子网络的多个节点之间建立和存储确定性量子纠缠...
- Ubuntu 使用XCB
- 怎样在计算机中找小键盘,笔记本怎么关小键盘【方法步骤】
- 单片机测量脉宽c语言程序,利用51系列单片机定时器功能实现测量脉冲宽度
- 2048游戏英雄榜java_2048游戏攻略 2048分数排行榜详解
- python-CST MWS自动采样
热门文章
- IDEA把Springboot打成可执行jar包,内嵌tomcat 这个可以用
- 从oracle里面取直,45个非常有用的 Oracle 查询语句小结
- matlab eval 不显示,matlab中 eval(command); 运算符无效的问题
- 转:json与map互转
- Java中synchronized同步块的执行流程
- java序列化和反序列化_Java恶意序列化背后的历史和动机
- 动态代码生成 静态代码生成_将速度提升到自己的个人代码生成器中
- spring内容协商管理_Spring框架中的内容协商
- 如何连接oracle xe_为什么应始终将连接池与Oracle XE一起使用
- grpc 流式传输_编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中...