一遇到的神奇的事情
使用 jpa 操作数据库, 当我使用 findAll() 方法查处一个 List 的对象后, 给对这个 list 的实体进行了一些操作, 并没有调用 update 或者 saveOrUpdate 方法, 更改后的数据却神奇的保存到数据库里面去了
最后简单粗暴的解决办法是把这份从数据里面查出来的 List 复制了一份, 然后再操作, 再返回数据就正常了, 数据库也没更新后面找了资料才发现是 jpa 是对 hibernate 的封装, 底层是 hibernate, 这是 hibernate 的持久状态搞的鬼
二 hibernate 的三种状态
1. 瞬时状态 (Transient)
当我们通过 Java 的 new 关键字来生成一个实体对象时, 这时这个实体对象就处于自由状态, 如下:
- 1
- Customer customer=new Customer(zx,27,images);
这时 customer 对象就处于自由状态, 为什么说 customer 对象处于自由状态呢? 这是因为, 此时 customer 只是通过 JVM 获得了一块内存空间, 还并没有通过 Session 对象的 save() 方法保存进数据库, 因此也就还没有纳入 Hibernate 的缓存管理中, 也就是说 customer 对象现在还自由的游荡于 Hibernate 缓存管理之外所以我们可以看出自由对象最大的特点就是, 在数据库中不存在一条与它对应的记录
瞬时对象特点:
不和 Session 实例关联
在数据库中没有和瞬时对象关联的记录
2. 持久状态 (Persistent)
持久化对象就是已经被保存进数据库的实体对象, 并且这个实体对象现在还处于 Hibernate 的缓存管理之中这是对该实体对象的任何修改, 都会在清理缓存时同步到数据库中如下所示:
- Customer customer=new Customer(zx,27,images);
- tx=session.beginTransaction();
- session.save(customer);
- customer=(Customer)session.load(Customer.class,1);
- customer.setAge(28);
- tx.commit();
这时我们并没有显示调用 session.update() 方法来保存更新, 但是对实体对象的修改还是会同步更新到数据库中, 因为此时 customer 对象通过 save 方法保存进数据库后, 已经是持久化对象了, 然后通过 load 方法再次加载它, 它仍然是持久化对象, 所以它还处于 Hibernate 缓存的管理之中, 这时当执行 tx.commit() 方法时, Hibernate 会自动清理缓存, 并且自动将持久化对象的属性变化同步到到数据库中
持久的实例在数据库中有对应的记录, 并拥有一个持久化标识 (identifier).
持久对象总是与 Session 和 Transaction 相关联, 在一个 Session 中, 对持久对象的改变不会马上对数据库进行变更, 而必须在 Transaction 终止, 也就是执行 commit() 之后, 才在数据库中真正运行 SQL 进行变更, 持久对象的状态才会与数据库进行同步在同步之前的持久对象称为脏 (dirty) 对象
瞬时对象转为持久对象:
通过 Session 的 save() 和 saveOrUpdate() 方法把一个瞬时对象与数据库相关联, 这个瞬时对象就成为持久化对象
使用 fine(),get(),load() 和 iterater() 待方法查询到的数据对象, 将成为持久化对象
持久化对象的特点:
和 Session 实例关联
在数据库中有和持久对象关联的记录
3. 脱管状态 (Detached)
当一个持久化对象, 脱离开 Hibernate 的缓存管理后, 它就处于游离状态, 游离对象和自由对象的最大区别在于, 游离对象在数据库中可能还存在一条与它对应的记录, 只是现在这个游离对象脱离了 Hibernate 的缓存管理, 而自由对象不会在数据库中出现与它对应的数据记录如下所示:
- Customer customer=new Customer(zx,27,images);
- tx=session.beginTransaction();
- session.save(customer);
- customer=(Customer)session.load(Customer.class,1);
- customer.setAge(28);
- tx.commit();
- session.close();
当 session 关闭后, customer 对象就不处于 Hibernate 的缓存管理之中了, 但是此时在数据库中还存在一条与 customer 对象对应的数据记录, 所以此时 customer 对象处于游离态
与持久对象关联的 Session 被关闭后, 对象就变为脱管对象对脱管对象的引用依然有效, 对象可继续被修改
脱管对象特点:
本质上和瞬时对象相同
只是比爱瞬时对象多了一个数据库记录标识值 id.
持久对象转为脱管对象:
当执行 close() 或 clear(),evict() 之后, 持久对象会变为脱管对象
瞬时对象转为持久对象:
通过 Session 的 update(),saveOrUpdate() 和 lock() 等方法, 把脱管对象变为持久对象
三三种状态的转换
四举例子
结合 save(),update(),saveOrUpdate() 方法说明对象的状态
(1) Save() 方法将瞬时对象保存到数据库, 对象的临时状态将变为持久化状态当对象在持久化状态时, 它一直位于 Session 的缓存中, 对它的任何操作在事务提交时都将同步到数据库, 因此, 对一个已经持久的对象调用 save() 或 update() 方法是没有意义的如:
- Student stu = new Strudnet();
- stu.setCarId(200234567);
- stu.setId(100);
- // 打开 Session, 开启事务
- session.save(stu);
- stu.setCardId(20076548);
- session.save(stu); // 无效
- session.update(stu); // 无效
- // 提交事务, 关闭 Session
(2) update() 方法两种用途重新关联脱管对象为持久化状态对象, 显示调用 update() 以更新对象调用 update() 只为了关联一个脱管对象到持久状态, 当对象已经是持久状态时, 调用 update() 就没有多大意义了如:
- // 打开 session , 开启事务
- stu = (Student)session.get(Student.class,123456);
- stu.setName(Body);
- session.update(stu); // 由于 stu 是持久对象, 必然位于 Session 缓冲中,
对 stu 所做的变更将 // 被同步到数据库中所以 update() 是没有意义的, 可以不要这句效果一样的
// 提交事务, 关闭 Session
Hibernate 总是执行 update 语句, 不管这个脱管对象在离开 Session 之后有没有更改过, 在清理缓存时 Hibernate 总是发送一条 update 语句, 以确保脱管对象和数据库记录的数据一致, 如:
- Student stu = new Strudnet();
- stu.setCarId(1234);
- // 打开 Session1, 开启事务
- session1.save(stu);
- // 提交事务, 关闭 Session1
- stu.set(4567); // 对脱管对象进行更改
- // 打开 Session2, 开启事务
- session2.update(stu);ssh
- // 提交事务, 关闭 Session2
注: 即使把 session2.update(stu); 这句去掉, 提交事务时仍然会执行一条 update() 语句
如果希望只有脱管对象改变了, Hibernate 才生成 update 语句, 可以把映射文件中 标签的 select-before-update 设为 true, 这种会先发送一条 select 语句取得数据库中的值, 判断值是否相同, 如果相同就不执行 update 语句不过这种做法有一定的缺点, 每次 update 语句之前总是要发送一条多余的 select 语句, 影响性能对于偶尔更改的类, 设置才是有效的, 对于经常要更改的类这样做是影响效率的
(3) saveOrUpdate() 方法兼具 save() 和 update() 方法的功能, 对于传入的对象, saveOrUpdate() 首先判断其是脱管对象还是临时对象, 然后调用合适的方法
我特意整理了一下, 里面的技术不是靠几句话就能讲清楚, 所以干脆找朋友录制了一些视频, 很多问题其实答案很简单, 但是背后的思考和逻辑不简单, 要做到知其然还要知其所以然如果想学习 Java 工程化高性能及分布式深入浅出性能调优 Spring,MyBatis,Netty 源码分析的朋友可以加我新建的 Java 群: 650385180, 群里有阿里大牛直播讲解技术, 以及 Java 大型互联网技术的视频免费分享给大家
参考
Hibernate 实体对象的状态及转化 by javacoffe
注: 喜欢的朋友可以点赞加关注, 一起学习进步
来源: http://www.jianshu.com/p/87b1053e8bd3