您的位置:首页 > 其它

不容易理解的 lock 和 merge

2013-10-07 23:16 393 查看

Hibernate:不容易理解的 lock 和 merge

目录

背景Lock官方的注释LockMode.NONELockMode.READLockMode.UPGRADEMerge官方注释detached 对象测试unsaved 对象测试备注

背景返回目录

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);


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

执行乐观锁检查,然后执行。

提升为悲观锁,然后执行。

将一个透明的实例(脱钩)和 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 有两个职责:

如果对象为 unsaved,对对象的拷贝执行 save 方法,返回拷贝的对象。

如果对象为 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 已经被标记为过时了,可是为啥没有提示其替代方法呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: