Lock Mode Type 之 Optimistic 使用场景
来源:互联网 发布:比易企秀好用的软件 编辑:程序博客网 时间:2024/06/14 18:42
转载自:http://blog.csdn.net/u012807459/article/details/52186702
JPA规范中,Lock Mode的值中包含了Optimistic, 一看就知道是用于乐观锁控制, 但是我一直被这个问题困扰,原因在于,在Entity中,已经使用@Version做了乐观锁控制,hibernate会自动更新比对,version值,那么设置Lock Mode 为Optimistic又有何用处呢?
先看一段代码
@PersistenceContext EntityManager entityManager; @Transactional() public Order t3(String str) { Order order67 = entityManager.find(Order.class, 67L, LockModeType.OPTIMISTIC); order67.setCancelReason(str); return order67; }
这段代码中使用了entity manager查询order,并且指定了乐观锁,然后在更新order,最初我以为这段代码会触发两条sql语句
select ... from `order` ...;update `order` set .... where id = ? and version = ?;
但是出乎我意料的是,我看到了第三条sql语句
select version from `order` where id = ?;
于是乎我在find时,去除了Optimistic的配置, 发现这第三条sql就不会触发。我百思不得其解,这Optimistic如同鸡肋一样。无意中找到在stack overflow上找到一篇帖子,看到其中一段对话,豁然开朗(链接)在文章中,有一段话是重点,我在这里黏贴出来
Normally you would never use the lock() API for optimistic locking. JPA will automatically check any version columns on any update or delete.The only purpose of the lock() API for optimistic locking is when your update depends on another object that is not changed/updated. This allows your transaction to still fail if the other object changes.When to do this depends on the application and the use case. OPTIMISTIC will ensure the other object has not been updated at the time of your commit. OPTIMISTIC_FORCE_INCREMENT will ensure the other object has not been updated, and will increment its version on commit.Optimistic locking is always verified on commit, and there is no guarantee of success until commit. You can use flush() to force the database locks ahead of time, or trigger an earlier error.
上面提到了Lock Mode Type 的 Optimistic类型的使用场景, 用中国话来说就是,在一个事务中,A对象的改变依赖于B对象,如果B对象在A的事物期间内发生了改变,那么A所在的事物将失败并且回滚。这种情况下就可以使用entityManager.lock(B,OPTIMISTIC)对B对象使用乐观锁。这一句话的作用在于,它会在A对象更改后,但事物提交前,查询一次B对象的version并做比对,如果比对成功A的事物保存成功,否则A事物失败,回滚。
继续看另一端代码
@PersistenceContext EntityManager entityManager; @Transactional() public Order test(String str) { Order order67 = entityManager.find(Order.class, 67L); order67.setCancelReason(str); Order order66 = entityManager.find(Order.class, 66L); entityManager.lock(order66, LockModeType.OPTIMISTIC); return order67; }
这段代码中,查询出了order67和order66, order67在其事务期间,如果order66发生变化,order67的事物将失败。代码中entityManager.lock(order66, LockModeType.OPTIMISTIC);这一句给order66加了乐观锁,所以事物提交之前,会先check order66的version,来判断order66是否被修改。为了配合实验,在数据库执行如下代码(假定order66的version值为12)
start transaction;select * from `order` where id = 67 for update;update `order` set version = 13 where id = 66;
开启事务, 使用排它锁将order67锁住,再更新order66对应的version,暂时不要提交。然后通过API调用刚才的test函数,此时test函数会阻塞,因为order67刚才被排它锁锁住,test函数事务提交时,会阻塞在order67的更新操作上。此时回到MySQL 命令行 commit刚才的事务。按照最初的设想,在order67事务结束前,order66的version发生了变化,order67应当提交失败,函数应该会抛出ObjectOptimisticLockingFailureException,但是我却意外地发现函数执行成功了,触发了四条sql语句
select order67select order66update order67select version from order67
这与我们之前讲的明显不一样,后来我突然意识到mysql的默认事务隔离级别是repeatable-read,那么就算其他事务提交,原有已开启的事务,是读不到变化的值。所以在这里我重新修改了函数,代码如下
@PersistenceContext EntityManager entityManager; @Transactional(isolation = Isolation.READ_COMMITTED) public Order t3(String str) { Order order67 = entityManager.find(Order.class, 67L); order67.setCancelReason(str); Order order66 = entityManager.find(Order.class, 66L); entityManager.lock(order66, LockModeType.OPTIMISTIC); return order67; }
这段代码在@Transactional指定了isolation为READ_COMMITTED,此时再重复刚才的试验,程序如预期的一样抛出了ObjectOptimisticLockingFailureException。
关于Locking read(lock in share mode 和 for update),可以上mysql官网查看,里面讲的很清楚(友情链接)。
意外发现了一篇和我这篇比较相像的文章,链接在这里,我大致浏览了下,基本是对的,作者最后貌似忘了将数据库隔离级别更改为read-committed。
我又陆续看了作者的几篇文章讲的真好,这篇讲的是OPTIMISTIC-INCREMENT的使用场景,非常之贴切。
极力推荐这位大牛的博客,有事没事可以去转转
- Lock Mode Type 之 Optimistic 使用场景
- Lock Mode Type 之 Optimistic 使用场景
- Optimistic lock
- hibernate中的optimistic-lock(...
- hibernate中的optimistic-lock(...
- 乐观锁(Optimistic Lock)之version(版本号)与timestamp(时间戳)配置解读
- Lock Mode
- SAP Lock & Lock Mode
- How to Determine The Lock Type and Mode from an Enqueue Wait
- ORACLE基础之oracle锁(oracle lock mode)详解
- ORACLE基础之oracle锁(oracle lock mode)详解
- hibernate lock mode
- Know Oracle Lock Mode
- ORACLE-LOCK MODE
- Hibernate中的悲观锁(pessimistic lock)和乐观锁(optimistic lock)
- Hibernate 中的悲观锁( pessimistic lock )和乐观锁( optimistic lock )
- launch mode应用场景
- launch mode 应用场景
- 剖析Mysql的InnoDB索引
- Maya2017无法导出fbx文件
- 21.单例模式
- 深入学习java8二(函数式接口)
- POJ 2606 Rabbit hunt 笔记
- Lock Mode Type 之 Optimistic 使用场景
- linux的mysql数据库的常用操作
- map 按键按值排序
- 如何防止数据库的编码格式跟项目编码格式不一致产生乱码, 怎么让数据库的编码格式跟项目编码格式保持一致
- 新手学习-Tcp的服务端与客户端的登录注册系统
- 22.桥接模式
- hdu 1075 字典树搜索
- PAT乙级1001. 害死人不偿命的(3n+1)猜想 (15)
- css一些常用的样式