jpa mysql乐观锁_JPA @Lock(value = LockModeType.PESSIMISTIC_WRITE) 悲观锁防坑

2023年8月2日11:07:48

前提:

由于业务需要在entity Product已经实现了@version的乐观锁的基础上再加上了悲观锁的控制

@Lock(value = LockModeType.PESSIMISTIC_WRITE)

Product findByType(String type);

详情描述:

但是当进行多请求的并发测试的时候发现程序第一个抢占findByType的请求能正常上锁,其它并发请求也正常进入等待,可是当第一个请求修改product并且提交事务释放锁的时候,其它等待请求准备上锁的时候却抛出了乐观锁的错误,为什么会出现这种错误呢?

解答:

JPA 提供的@Lock 不是直接对findByType生成的对应查询语句后面加for update上锁,而是按照下面的顺序来上锁的:

执行查询语句: select * from product where type = ?

查询结果(id, type, version): [1001, 'NEW', 1]

通过查询出来的id, version在执行以下查询

select * from product where product id = 1001 and version = 1

如果步骤2查询有数据返回的话就生成下面的for update的查询SQL上锁, 如果没有就抛出乐观锁异常。

select * from product where product id = 1001 and version = 1 for update

根据@Lock的上述执行原理,当触发多请求并发的时候,所有请求都同步执行了上述1的查询操作,当执行步骤2,3的时候先上锁的请求修改了数据和版本后,后续请求在旧的version就查询不出来数据就抛出了乐观锁异常了。

建议:

一般情况下尽量避免使用悲观锁,对系统开销很大,如果不得已需要用到的话还是直接写for update的SQL直接上锁。

  • 作者:Fl4me
  • 原文链接:https://blog.csdn.net/weixin_42138716/article/details/114315406
    更新时间:2023年8月2日11:07:48 ,共 743 字。