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

前提:

由于业务需要在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直接上锁。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@Data @AllArgsConstructor @NoArgsConstructor @Builder @Table(name = "advert") public class Advert { /** * 主键 / @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @ApiModelProperty(value = "广告唯一id") private Integer id; /* * 广告名称 / @ApiModelProperty(value = "广告名称") @NotBlank(message = "广告名称不可为空", groups = {AddGroup.class, UpdateGroup.class}) private String name; /* * 广告位置ID / @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "position_id") private AdPosition position; /* * 广告图片ID / @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "media_id") private MediaFile media; /* * 开始日期 / @Column(name = "start_date") @ApiModelProperty(value = "开始日期") @NotNull(message = "开始日期不可为空", groups = {AddGroup.class}) private Date startDate; /* * 结束日期 / @Column(name = "end_date") @ApiModelProperty(value = "结束日期") @NotNull(message = "结束日期不可为空", groups = {AddGroup.class}) private Date endDate; /* * 广告链接 / @ApiModelProperty(value = "广告链接") @NotBlank(message = "广告链接不可为空", groups = {AddGroup.class}) private String link; /* * 广告状态:0:未启用,1:已启用,2:已结束 / @ApiModelProperty(value = "广告状态") @NotNull(message = "广告状态不可为空", groups = {UpdateGroup.class}) private Integer status; /* * 创建时间 / @Column(name = "create_time") @ApiModelProperty(value = "创建时间") private Date createTime; /* * 更新时间 */ @Column(name = "update_time") @ApiModelProperty(value = "更新时间") private Date updateTime; },对这个类的对象进行添加和修改时,因为在server层有大量重复代码,如何简化代码并避免并发问题
06-01

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值