背景

lock 和 merge 在字面上很容易理解它们的语义,不过它们的实际行为所代表的语义范围要大一点,本文就简单的记录下来,还请朋友们多批评和指正。

Lock

官方的注释

  1. /**
  2. * Obtain the specified lock level upon the given object. This may be used to
  3. * perform a version check (<tt>LockMode.READ</tt>), to upgrade to a pessimistic
  4. * lock (<tt>LockMode.PESSIMISTIC_WRITE</tt>), or to simply reassociate a transient instance
  5. * with a session (<tt>LockMode.NONE</tt>). This operation cascades to associated
  6. * instances if the association is mapped with <tt>cascade="lock"</tt>.
  7. *
  8. * @param object a persistent or transient instance
  9. * @param lockMode the lock level
  10. *
  11. * @deprecated instead call buildLockRequest(LockMode).lock(object)
  12. */
  13. @Deprecated
  14. public void lock(Object object, LockMode lockMode);

根据注释可以知道其有三个职责:

  1. 执行乐观锁检查,然后执行。
  2. 提升为悲观锁,然后执行。
  3. 将一个透明的实例(脱钩)和 Session 进行关联。

注意:1 和 2 都会执行 3。

LockMode.NONE

测试代码

  1. package demo;
  2.  
  3. import model.*;
  4. import org.hibernate.*;
  5.  
  6. /*
  7. * lock 会将处于 transparent 状态的对象变为 persisted。
  8. */
  9. public class LockDemo implements Demo {
  10.  
  11. @Override
  12. public void run() {
  13. SessionHelper.read(new SessionAction() {
  14. User user = UserHelper.createUser();
  15.  
  16. @SuppressWarnings("deprecation")
  17. @Override
  18. public void action(Session session) {
  19. session.lock(user, LockMode.NONE);
  20.  
  21. // 为了测试执行 lock 后实例是否变为持久化状态。
  22. user = (User) session.get(User.class, user.getId());
  23. }
  24.  
  25. });
  26. }
  27. }

说明:上例执行后没有任何 SQL 输出。

LockMode.READ

测试代码

  1. package demo;
  2.  
  3. import model.*;
  4. import org.hibernate.*;
  5.  
  6. /*
  7. * lock 会将处于 transparent 状态的对象变为 persisted。
  8. */
  9. public class LockDemo implements Demo {
  10.  
  11. @Override
  12. public void run() {
  13. SessionHelper.read(new SessionAction() {
  14. User user = UserHelper.createUser();
  15.  
  16. @SuppressWarnings("deprecation")
  17. @Override
  18. public void action(Session session) {
  19. session.lock(user, LockMode.READ);
  20.  
  21. // 为了测试执行 lock 后实例是否变为持久化状态。
  22. user = (User) session.get(User.class, user.getId());
  23. }
  24.  
  25. });
  26. }
  27. }

输出结果

  1. /* READ lock model.User */ select
  2. Id
  3. from
  4. Users
  5. where
  6. Id =?
  7. and Version =?

说明:上例执行了乐观锁检查,我还没有测试检查失败的场景,估计是会抛出异常。

LockMode.UPGRADE

测试代码

  1. package demo;
  2.  
  3. import model.*;
  4. import org.hibernate.*;
  5.  
  6. /*
  7. * lock 会将处于 transparent 状态的对象变为 persisted。
  8. */
  9. public class LockDemo implements Demo {
  10.  
  11. @Override
  12. public void run() {
  13. SessionHelper.read(new SessionAction() {
  14. User user = UserHelper.createUser();
  15.  
  16. @SuppressWarnings("deprecation")
  17. @Override
  18. public void action(Session session) {
  19. session.lock(user, LockMode.UPGRADE);
  20.  
  21. // 为了测试执行 lock 后实例是否变为持久化状态。
  22. user = (User) session.get(User.class, user.getId());
  23. }
  24.  
  25. });
  26. }
  27. }

输出结果

  1. /* UPGRADE lock model.User */ select
  2. Id
  3. from
  4. Users
  5. where
  6. Id =?
  7. and Version =? for update

说明:上例将对象对应的数据库记录升级为悲观锁,由此可以保证修改的串行化。

Merge

官方注释

  1. /**
  2. * Copy the state of the given object onto the persistent object with the same
  3. * identifier. If there is no persistent instance currently associated with
  4. * the session, it will be loaded. Return the persistent instance. If the
  5. * given instance is unsaved, save a copy of and return it as a newly persistent
  6. * instance. The given instance does not become associated with the session.
  7. * This operation cascades to associated instances if the association is mapped
  8. * with {@code cascade="merge"}
  9. * <p/>
  10. * The semantics of this method are defined by JSR-220.
  11. *
  12. * @param object a detached instance with state to be copied
  13. *
  14. * @return an updated persistent instance
  15. */
  16. public Object merge(Object object);

根据注释可以知道 merge 有两个职责:

  1. 如果对象为 unsaved,对对象的拷贝执行 save 方法,返回拷贝的对象。
  2. 如果对象为 detached,将对象的状态拷贝到和对象的标识一样的持久化对象中,如果持久化对象不存在,就执行 get 方法将其加载。

detached 对象测试

测试代码

  1. package demo;
  2.  
  3. import model.*;
  4. import org.hibernate.*;
  5.  
  6. /*
  7. * merge 不会将参数变为持久化状态,而是使用参数修改 session 中的持久化对象,如果 session 中不包含持久化
  8. * 对象,就从数据库中加载一个,如果对象为 unsaved 状态,就对其拷贝执行 save。
  9. */
  10. public class MergeDemo implements Demo {
  11.  
  12. @Override
  13. public void run() {
  14. SessionHelper.execute(new SessionAction() {
  15. User user = UserHelper.createUser();
  16.  
  17. @Override
  18. public void action(Session session) {
  19. User newUser = new User();
  20. newUser.setId(user.getId());
  21. newUser.setUsername("shijiucha");
  22. newUser.setPassword(user.getPassword());
  23. newUser.setVersion(user.getVersion());
  24.  
  25. session.merge(newUser);
  26. }
  27.  
  28. });
  29. }
  30. }

输出结果

  1. begin transaction
  2. action
  3. Hibernate:
  4. /* load model.User */ select
  5. user0_.Id as Id1_2_0_,
  6. user0_.Version as Version2_2_0_,
  7. user0_.Username as Username3_2_0_,
  8. user0_.Password as Password4_2_0_
  9. from
  10. Users user0_
  11. where
  12. user0_.Id=?
  13. flush and commit
  14. Hibernate:
  15. /* update
  16. model.User */ update
  17. Users
  18. set
  19. Version=?,
  20. Username=?,
  21. Password=?
  22. where
  23. Id=?
  24. and Version=?

说明:上例先执行了 select 语句,然后执行了合并过程,因为有修改,在 flush 的时候产生了 update 语句。

unsaved 对象测试

测试代码

  1. package demo;
  2.  
  3. import model.*;
  4. import org.hibernate.*;
  5.  
  6. /*
  7. * merge 不会将参数变为持久化状态,而是使用参数修改 session 中的持久化对象,如果 session 中不包含持久化
  8. * 对象,就从数据库中加载一个,如果对象为 unsaved 状态,就对其拷贝执行 save。
  9. */
  10. public class MergeDemo implements Demo {
  11.  
  12. @Override
  13. public void run() {
  14. SessionHelper.execute(new SessionAction() {
  15. User user = UserHelper.createUser();
  16.  
  17. @Override
  18. public void action(Session session) {
  19. User newUser = new User();
  20. newUser.setId(user.getId());
  21. newUser.setUsername("shijiucha");
  22. newUser.setPassword(user.getPassword());
  23. //newUser.setVersion(user.getVersion());
  24.  
  25. session.merge(newUser);
  26. }
  27.  
  28. });
  29. }
  30. }

输出结果

  1. begin transaction
  2. action
  3. Hibernate:
  4. /* insert model.User
  5. */ insert
  6. into
  7. Users
  8. (Version, Username, Password)
  9. values
  10. (?, ?, ?)
  11. flush and commit

说明:上例只执行了 insert 语句,因为 user 是 unsaved 状态。

备注

hibernate 的注释写的真是漂亮。

另外说一句:lock 已经被标记为过时了,可是为啥没有提示其替代方法呢?

Hibernate:不容易理解的 lock 和 merge的更多相关文章

  1. 不容易理解的 lock 和 merge

    Hibernate:不容易理解的 lock 和 merge 目录 背景Lock官方的注释LockMode.NONELockMode.READLockMode.UPGRADEMerge官方注释detac ...

  2. Hibernate中load与get,update与merge方法的区别

    1.load()与get()的区别: (1)load()读取 User user = (User)session.load(User.class, userId); (2)get()读取 User u ...

  3. 深入理解SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE

    概念和区别 SELECT ... LOCK IN SHARE MODE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他session可以读取这些记录,也可以继续添加IS ...

  4. J2EE框架(Struts&Hibernate&Spring)的理解

    SSH:Struts(表示层)+Spring(业务层)+Hibernate(持久层)Struts:Struts是一个表示层框架,主要作用是界面展示,接收请求,分发请求.在MVC框架中,Struts属于 ...

  5. hibernate entitymanager的理解

    hibernate EntityManager是围绕提供JPA编程接口的Hibernate Core的一个包装,支持JPA实体实例的生命周期,并允许你用标准的JavaPersistence查询语言编写 ...

  6. 说说自己对hibernate一级、二级、查询、缓存的理解。

    说说自己对hibernate一级.二级.查询.缓存的理解. 2016-03-14 21:36 421人阅读 评论(0) 收藏 举报  分类: web开发(19)  版权声明:本文为博主原创文章,未经博 ...

  7. JavaEE Hibernate初级概念

    1.  Hibernate 是连接Java应用程序和关系数据库的中间件: 对JDBC API进行了封装.负责Java对象的持久化: 在三层软件架构中它位于持久层(数据访问层),封装了所有数据访问细节, ...

  8. [Java面试八]Hibernate总结以及在面试中的一些问题.

    1.为什么要使用Hibernate开发你的项目呢?Hibernate的开发流程是怎么样的? 为什么要使用 ①.对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码. ②.Hiber ...

  9. Hibernate(七):*.hbm.xml配置文件中Set三个属性

    背景: 在上一篇文章中实现双向关联时,其中在Customer.java中我们使用了java.util.List<Order>来关联多的Order.其实还有另外一种实现方法:使用java.u ...

随机推荐

  1. Kail Linux渗透测试之测试工具Armitage

    Kali Linux下的Armitage是一个很强大的渗透工具,图形化操作页面,但我们把kali linux装在虚拟机里面,然后再启动armitage就会出现一个error,他会给你一个message ...

  2. LightOJ 1370- Bi-shoe and Phi-shoe (欧拉函数)

    题目大意:一个竹竿长度为p,它的score值就是比p长度小且与且与p互质的数字总数,比如9有1,2,4,5,7,8这六个数那它的score就是6.给你T组数据,每组n个学生,每个学生都有一个幸运数字, ...

  3. RGW 系统吞吐量(TPS)、用户并发量、性能测试概念和公式

      一.系统吞度量要素: 一个系统的吞度量(承压能力)与request对CPU的消耗.外部接口.IO等等紧密关联. 单个reqeust 对CPU消耗越高,外部系统接口.IO影响速度越慢,系统吞吐能力越 ...

  4. 洛谷P2676 超级书架 题解

    题目传送门 题目一看就是贪心.C++福利来了:sort. 基本思路就是:要使奶牛最少那么肯定高的奶牛先啦. 直接排序一遍(从高到矮)然后while,搞定! #include<bits/stdc+ ...

  5. pymongo的一些操作

    参考:http://www.yiibai.com/mongodb/mongodb_drop_collection.html http://www.cnblogs.com/zhouxuchen/p/55 ...

  6. spring_150908_hibernate_id_sequence

    1.新建java工程:spring_150908_hibernate_id_sequence,添加相关jar包(spring.hibernate.ibatis)如下图所示: 2.实现实体类DogPet ...

  7. Java利用Redis实现消息队列

    应用场景 为什么要用redis?二进制存储.java序列化传输.IO连接数高.连接频繁 一.序列化 这里编写了一个java序列化的工具,主要是将对象转化为byte数组,和根据byte数组反序列化成ja ...

  8. 洛谷P2571 [SCOI2010]传送带 [三分]

    题目传送门 传送带 题目描述 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移 ...

  9. Java Web开发——JSP基本语法杂记

    在一个JSP页面中,可以包括指令标识.HTML代码.JavaScript代码.嵌入的Java代码.注释和JSP动作标识等内容.但是这些并不是JSP页面所必须的. 1 指令标识指令标识主要用于设定整个J ...

  10. Docker运行oracle12c注意事项

    title: docker运行oracle12c注意事项 date: 2019-03-27 13:42:34 categories: 数据库 author: mrzhou tags: docker 数 ...