工作中的一个功能,又遇到可能会发生数据库死锁的风险

功能的需求:

增加对商品订单的修改功能;也就是可以对订单中的商品进行更换及数量的修改;

我的预期编写方案是:

由于商品在下单中,进行了很多其他的数据库修改行为,例如扣除库存,统计,会员积分等等;所以我预想的是如下操作:

1.对订单进行整体回滚操作,例如删除统计,回滚库存,回滚会员积分余额等;

2.使用之前下单分离出的各个处理方法,重新对该订单下单,进行一系列操作;

于是,我意识到了一个问题,就是如此大的数据库修改操作,目前由于体量问题,又是在一个事务中完成,也就是有一个数据库长事务的操作,务必会引发死锁;

 

死锁发生的地方,只举出一个比较明显会出问题的地方,就是在订单修改和下单同时并发进行的时候;举例说明:

现有商品四种分别是:

A商品
B商品
C商品
D商品

下面假设发生并发行为:

管理员修改订单客户端下单
对C.D商品进行库存回滚修改 
 下单A.C商品 (此时由于修改订单原因,触发C商品的排他锁,客户端事务等待状态)
由于修改后,对A.B商品重新下单(此时由于客户端A商品占有锁,并且无法释放,导致客户端发生死锁,订单修改成功) 


 

同时如果加入了会员信息回滚,如果在同一事务中,一样也会发生死锁:

管理员修改订单客户端下单
回滚A会员余额;扣减A商品库存,
 并且扣减A会员余额; (此时处于等待状态)
回滚A商品库存;(此时发生死锁) 

 

原因:

其实也看出来了,就是一个资源循环占用锁,互相无法释放的原因导致的;

从上面可以看出,用最基本的方式对商品进行排序,使发生数据修改的资源有序化已经无法避免死锁;如果只是下单扣库存则可以避免死锁;但是像修改订单这个长事务,已经改变了有序性;

 

解决方案:

1.如果并发量不高,并且可以容忍死锁造成的一次单方失败,则可以保持不动;(mysql会认为回滚事务代价最小的一方回滚)

2.优化代码,减少事务的处理时间,降低并发;

3.如果可以将两次修改行为分离出来,进行有序化;例如将回滚商品和扣除商品分离出来,进行排序合并后一并更新;

4.对同一事物中,所有资源进行有序化修改;

5.对功能进行重构,例如使用消息等异步最终一致性方式,减少长事务的存在;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值