背景

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

Lock

官方的注释

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

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

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

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

LockMode.NONE

测试代码

 package demo;

 import model.*;
import org.hibernate.*; /*
* lock 会将处于 transparent 状态的对象变为 persisted。
*/
public class LockDemo implements Demo { @Override
public void run() {
SessionHelper.read(new SessionAction() {
User user = UserHelper.createUser(); @SuppressWarnings("deprecation")
@Override
public void action(Session session) {
session.lock(user, LockMode.NONE); // 为了测试执行 lock 后实例是否变为持久化状态。
user = (User) session.get(User.class, user.getId());
} });
}
}

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

LockMode.READ

测试代码

 package demo;

 import model.*;
import org.hibernate.*; /*
* lock 会将处于 transparent 状态的对象变为 persisted。
*/
public class LockDemo implements Demo { @Override
public void run() {
SessionHelper.read(new SessionAction() {
User user = UserHelper.createUser(); @SuppressWarnings("deprecation")
@Override
public void action(Session session) {
session.lock(user, LockMode.READ); // 为了测试执行 lock 后实例是否变为持久化状态。
user = (User) session.get(User.class, user.getId());
} });
}
}

输出结果

     /* READ lock model.User */ select
Id
from
Users
where
Id =?
and Version =?

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

LockMode.UPGRADE

测试代码

 package demo;

 import model.*;
import org.hibernate.*; /*
* lock 会将处于 transparent 状态的对象变为 persisted。
*/
public class LockDemo implements Demo { @Override
public void run() {
SessionHelper.read(new SessionAction() {
User user = UserHelper.createUser(); @SuppressWarnings("deprecation")
@Override
public void action(Session session) {
session.lock(user, LockMode.UPGRADE); // 为了测试执行 lock 后实例是否变为持久化状态。
user = (User) session.get(User.class, user.getId());
} });
}
}

输出结果

     /* UPGRADE lock model.User */ select
Id
from
Users
where
Id =?
and Version =? for update

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

Merge

官方注释

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

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

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

detached 对象测试

测试代码

 package demo;

 import model.*;
import org.hibernate.*; /*
* merge 不会将参数变为持久化状态,而是使用参数修改 session 中的持久化对象,如果 session 中不包含持久化
* 对象,就从数据库中加载一个,如果对象为 unsaved 状态,就对其拷贝执行 save。
*/
public class MergeDemo implements Demo { @Override
public void run() {
SessionHelper.execute(new SessionAction() {
User user = UserHelper.createUser(); @Override
public void action(Session session) {
User newUser = new User();
newUser.setId(user.getId());
newUser.setUsername("shijiucha");
newUser.setPassword(user.getPassword());
newUser.setVersion(user.getVersion()); session.merge(newUser);
} });
}
}

输出结果

 begin transaction
action
Hibernate:
/* load model.User */ select
user0_.Id as Id1_2_0_,
user0_.Version as Version2_2_0_,
user0_.Username as Username3_2_0_,
user0_.Password as Password4_2_0_
from
Users user0_
where
user0_.Id=?
flush and commit
Hibernate:
/* update
model.User */ update
Users
set
Version=?,
Username=?,
Password=?
where
Id=?
and Version=?

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

unsaved 对象测试

测试代码

 package demo;

 import model.*;
import org.hibernate.*; /*
* merge 不会将参数变为持久化状态,而是使用参数修改 session 中的持久化对象,如果 session 中不包含持久化
* 对象,就从数据库中加载一个,如果对象为 unsaved 状态,就对其拷贝执行 save。
*/
public class MergeDemo implements Demo { @Override
public void run() {
SessionHelper.execute(new SessionAction() {
User user = UserHelper.createUser(); @Override
public void action(Session session) {
User newUser = new User();
newUser.setId(user.getId());
newUser.setUsername("shijiucha");
newUser.setPassword(user.getPassword());
//newUser.setVersion(user.getVersion()); session.merge(newUser);
} });
}
}

输出结果

 begin transaction
action
Hibernate:
/* insert model.User
*/ insert
into
Users
(Version, Username, Password)
values
(?, ?, ?)
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. 使用jdk自带的工具native2ascii 转换Unicode字符和汉字

    1.控制台转换 1.1 将汉字转为Unicode: C:\Program Files\Java\jdk1.5.0_04\bin>native2ascii 测试 \u6d4b\u8bd5 1.2 ...

  2. Linux平台上SQLite数据库教程(一)——终端使用篇

    https://blog.csdn.net/u011192270/article/details/48031763 https://blog.csdn.net/fml1997/article/deta ...

  3. Hadoop(四)HDFS的高级API操作

    一 HDFS客户端环境准备 1.1 jar包准备 1)解压hadoop-2.7.6.tar.gz到非中文目录 2)进入share文件夹,查找所有jar包,并把jar包拷贝到_lib文件夹下 3)在全部 ...

  4. 2019.2.25 模拟赛T1【集训队作业2018】小Z的礼物

    T1: [集训队作业2018]小Z的礼物 我们发现我们要求的是覆盖所有集合里的元素的期望时间. 设\(t_{i,j}\)表示第一次覆盖第i行第j列的格子的时间,我们要求的是\(max\{ALL\}\) ...

  5. AC日记——[USACO5.4]奶牛的电信Telecowmunication 洛谷 P1345

    [USACO5.4]奶牛的电信Telecowmunication 思路: 水题: 代码: #include <cstdio> #include <cstring> #inclu ...

  6. LoadRunner监控Linux的三种方法

    方法一.LR + SiteScope/nmon 方法二.使用rstatd包 1.下载rpc.rstatd-4.0.1.tar.gz 2.解压缩 tar -zxvf rpc.rstatd-4.0.1.t ...

  7. 洛谷P4139 上帝与集合的正确用法 [扩展欧拉定理]

    题目传送门 上帝与集合的正确用法 题目描述 根据一些书上的记载,上帝的一次失败的创世经历是这样的: 第一天, 上帝创造了一个世界的基本元素,称做“元”. 第二天, 上帝创造了一个新的元素,称作“α”. ...

  8. SpringBoot学习(二)

    MyBatis是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.spring Boot 是能支持快速创建 Spring 应用的 ...

  9. [BZOJ3676][APIO2014]回文串(Manacher+SAM)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3097  Solved: 1408[Submit][Statu ...

  10. 【8.22校内测试】【数学】【并查集】【string】

    今天的t2t3能打出来80分的暴力都好满足啊QwQ.(%%%$idy$ 今天的签到题,做的时候一眼就看出性质叻qwq.大于11的所有数分解合数都可以用4.6.9表示,乱搞搞就可以了. #include ...