JPA乐观锁(READ)解释

时间:2014-03-02 01:41:30

标签: multithreading jpa

我正在阅读一篇关于jpa锁定的文章。链接:https://blogs.oracle.com/carolmcdonald/entry/jpa_2_0_concurrency_and

在关于乐观锁(READ)的部分中,作者有代码片段,其中说明事务2因异常而被回滚。基于代码片段,事务2在事务1修改dep的名称之前获取dep上的锁。如果我从学校正确理解讲座,从获得锁定(文章中的em.lock)到锁定被释放(文章中的tx2.commit),行动(在文章中将员工提高10%)是原子,这意味着dep的名称不能设置为“MarketEng”,因此,员工获得10%的提升。在tx2提交后,它释放锁定,dep的名称最终设置为“MarketEng”。因此,没有事务被回滚并且它是线程安全的。

我理解正确吗?如果没有,请向我解释一下作者的意思是“e1获得他不配的加薪”。

1 个答案:

答案 0 :(得分:0)

乐观锁定有点用词 - 没有实际的锁定。您描述的行为(tx2中的em.lock将阻止tx1中的更新)是一种悲观锁定。在JPA中,悲观锁转换为DB中具有select .. for update的行级锁。乐观的锁不会。

乐观锁定使用计数器在对象更新时进行通信,或验证是否发生了更新。写入总是递增计数器。使用LockMode.OPTIMISTIC进行读取将在提交时检查计数器,如果值已更改,则会因异常或回滚而失败。

乐观锁定的一点是你“乐观地”认为在同一个对象实例上的这种冲突在实践中很少见,因此最好冒失败提交,而不是通过实际的行级锁减慢一切,并且担心死锁。

在此特定示例中,有两个并发运行的事务:

  • tx1将部门名称从“Eng”更改为“MarketEng”
  • tx2'锁定'部门(这不是真正的锁定,但承诺在tx2.commit上检查部门的版本计数器)
  • tx2仅在deparment name =“Eng”时才向员工发放加薪。
    • tx1已经改变了但尚未提交
    • tx2仍有部门名称='Eng',因此员工可能会加薪
  • tx1提交更改 - 这会增加部门的计数器
  • tx2检查版本计数器,发现它已更改,然后回滚

但是,这个例子存在一些缺陷,因为从业务或用户的角度来看,影响与直觉不匹配 - 如果tx1在tx2提交后刚刚启动,则部门名称会在员工获得加薪后立即更改。如果名称提前一瞬间改变,为什么重要?

我喜欢使用的类比是版本控制系统。大多数版本控制系统(如svn和git)都使用某种形式的乐观锁定。允许两个人同时在同一个文件上开始工作,但是当您尝试提交其他人首先提交的文件时,您会收到错误。其他版本控制系统,如Visual SourceSafe(至少我最后一次使用它)使用悲观锁定,你必须检查一个文件进行编辑,结账是一个独占锁 - 没有其他人可以检查相同的文件编辑,直到你提交。