乐观锁和悲观锁在实际开发中的应用

背景

在系统开发中,新增数据和更新数据是很常见的业务行为,有时更新数据还会附带新增数据的行为,面对这些业务行为,系统必须做到接口的幂等性和关联数据的一致性,下面先针对两种业务的常见错误写法和正确写法。

新增操作

常见业务场景:A系统给B系统同步业务数据,业务数据中有一个唯一字段businessCode作为幂等字段。

常见错误处理

在这里插入图片描述
先根据businessCode查询数据库,如果数据不为空,则新增数据,这种写法在没有什么并发的时候完全没问题,但是有并发量的时候就会产生脏数据,原因是在T1线程执行红色代码块的时候,T2线程以迅雷不及掩耳之势跑完了,这时T1也能正常插入,所以脏数据也就产生了

优化处理

新增businessCode字段作为唯一索引,不需要查询数据库判断,直接交给数据库层面处理。
在这里插入图片描述

更新处理

常见业务:系统中有一张异常订单表A,订单表A有字段status,如果status为1,代表待处理,就能对该订单做异常登记处理,生成异常登记记录表B,并更新订单表status为2,代表已处理。

常见错误处理

在这里插入图片描述
用户做订单异常登记时,会回传订单id和登记信息作为接口参数,先根据订单id查询订单,再判断订单状态,如果订单状态为待处理,则根据订单id和登记信息生成异常登记记录并插入记录表B。

这种写法在没有什么并发的时候完全没问题,但是有并发量的时候就会产生脏数据,原因是在当T1线程执行红色代码块的时候,T2线程已经将订单状态修改了并新增了异常登记记录,T1线程就会插入脏数据

优化处理

乐观锁方案

将更新语句改为update A set status = 2 where id = 1 and status = 1,并判断返回影响行数,如果影响行数不符合预期则抛异常让数据库回滚已经执行的sql语句。

优点:这种方案本质上是乐观锁的处理方案,适合读多写少的场景,可以根据更新语句返回的数据判断,做合适的业务处理,比如重试,抛异常等;
缺点:如果没有预期状态status值则无法完成这种操作,必须新增真正的乐观锁字段version,如果需要回滚的业务操作太多,则会加大数据库压力。

悲观锁方案 update

在这里插入图片描述
先根据订单id和预期状态更新订单,再判断影响行数是否等于预期行数,如果符合预期,则根据订单id和登记信息生成异常登记记录并插入记录表B。

优点:这种方案本质上是悲观锁的处理方案,适合读少写多的场景,当一个事务执行update的操作的时候,会在这行记录上加锁,阻塞其他事务的update操作;
缺点:如果订单表不止更新状态字段,且其他字段的更新需要额外的计算,且异常登记记录表也需要其他额外字段,这种方案就没法做了。

悲观锁方案 select for update

在这里插入图片描述
先使用select for update查询订单表A并加锁,在根据查询返回的字段进行逻辑计算,并生成异常登记记录,然后插入数据,最后更新订单状态,这种本质上也是悲观锁方案,适用于更新操作时需要复杂的逻辑计算。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值