Hibernate:不容易理解的 lock 和 merge

背景返回目录

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 已经被标记为过时了,可是为啥没有提示其替代方法呢?

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

  1. Hibernate:不容易理解的 lock 和 merge

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

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

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

  3. Select for update/lock in share mode 对事务并发性影响

    select for update/lock in share mode 对事务并发性影响 事务并发性理解 事务并发性,粗略的理解就是单位时间内能够执行的事务数量,常见的单位是 TPS( transa ...

  4. Mysql加锁过程详解(4)-select for update/lock in share mode 对事务并发性影响

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  5. Pthreads并行编程之spin lock与mutex性能对比分析(转)

    POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API.线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用 ...

  6. 学习动态性能表(8)--v$lock&v$locked_object

    学习动态性能表 第八篇-(1)-V$LOCK  2007.5.31 这个视图列出Oracle 服务器当前拥有的锁以及未完成的锁或栓锁请求.如果你觉着session在等待等待事件队列那你应该检查本视图. ...

  7. iOS 多线程的简单理解(4) 线程锁的简单使用

    要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全 推荐一个原文链接 是关于 线程锁的基本使用的  http://blog.csdn.net/qq_30513483/article/detai ...

  8. 多线程设计模式——Read-Write Lock模式和Future模式分析

    目录 多线程程序评价标准 任何模式都有一个相同的"中心思想" Read-Write Lock 模式 RW-Lock模式特点 冲突总结 手搓RW Lock模式代码 类图 Data类 ...

  9. 图解 Git 基本命令 merge 和 rebase

    Git 基本命令 merge 和 rebase,你真的了解吗? 前言 Git 中的分支合并是一个常见的使用场景. 仓库的 bugfix 分支修复完 bug 之后,要回合到主干分支,这时候两个分支需要合 ...

随机推荐

  1. 如何使用Linq或EF来对数据去重——Distinct方法详解

    刚开始接触LINQ时使用distinct去重时和大家一样遇到了一些麻烦,很感谢 http://www.cnblogs.com/A_ming/archive/2013/05/24/3097062.htm ...

  2. 魔兽世界服务器Trinitycore分析二:auth server的main函数

    TrinityCore由生成两个运行文件authserver和world server以及一堆DLL(或so)文件的子项目组成(先忽略map_extractor等几个工具项目). authserver ...

  3. 【百度地图API】如何利用地图API制作汽车沿道路行驶的动画?——如何获得道路层数据

    原文:[百度地图API]如何利用地图API制作汽车沿道路行驶的动画?--如何获得道路层数据 有几个做汽车导航的朋友问我说,他们想在地图上制作一辆车沿着道路行驶的动画.可是,百度地图的道路数据并没有公开 ...

  4. 【百度地图API】发布静态图API啦!只需一个网址,即可展示定制百度地图!

    原文:[百度地图API]发布静态图API啦!只需一个网址,即可展示定制百度地图! 摘要: 百度地图静态图API!您无须执行任何“特殊”操作便可在网页上显示此图片. 不需要 JavaScript.我们只 ...

  5. c# 替换非法字符

    保存文件的时候,文件名不允许非法字符. public string ReplaceSpecialCharacter(string str)        {            List<ch ...

  6. easyui 小知识

    默认为今天 $(document).ready(function () {        $(function () {            var curr_time = new Date();  ...

  7. Android NDK的C++11标准支持

    C++11于Android NDK它已被支持,本文介绍了如何NDK添加C++11支持标准. 在开源项目Cocos2d-x于,他已经加入C++11支持标准. 1.改动Application.mk文件,加 ...

  8. Redis 优化查询性能

    一次使用 Redis 优化查询性能的实践   应用背景 有一个应用需要上传一组ID到服务器来查询这些ID所对应的数据,数据库中存储的数据量是7千万,每次上传的ID数量一般都是几百至上千数量级别. 以前 ...

  9. 一步一步写算法(之prim算法 下)

    原文:一步一步写算法(之prim算法 下) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前两篇博客我们讨论了prim最小生成树的算法,熟悉 ...

  10. sql注入工具sqlmap使用参数说明

    Options(选项):--version 显示程序的版本号并退出-h, --help 显示此帮助消息并退出-v VERBOSE 详细级别:0-6(默认为1)Target(目标):以下至少需要设置其中 ...