并发场景下数据不一致性解决方案

背景

在日常生活中,涉及购买东西的场景下,卖方需要自己有一个记账本,记录物品和价格以及购买记录的一些信息。假设有一个价格管理系统,记录了每个物品对应的价格和购买次数,以及这些物品什么时候被买走。有两张表,一张是物品价格表goods_price,一张是购买记录表buy_record。

goods_price

idgood_namebuy_countstock
1铅笔210

buy_record

idgood_namebuy_timebuyer
1铅笔2021-09-15jack
2铅笔2021-08-15tom

每当有人买东西的时候, buy_record就新增一条记录,并且 goods_price 中的购买次数会增加;有人退东西的时候,buy_record就删除一条记录,并且 goods_price 中的购买次数会减少。
每个物品有一定数目的库存stock,卖出的数量不能超过这个库存数,也不能小于零。

遇到的问题

如果到了开学的时候,铅笔的购买量变大,同一时间有很多人都在购买铅笔,也有人退掉不满意的铅笔,那么 goods_price 中的购买次数这个字段,就有可能由于并发操作而发生数据错误。
比如两个人同时抢购最后一根铅笔,库存显示都是1,此时他们同时下了单,卖出的次数就超过了库存数,就发生了数据错误。
(问题延伸:如果每个人只能买一次,不可以短时间内重复下单/由于网络原因导致重复请求,怎么解决?【考虑在数据库中判断购买记录是否重复】)

解决方案

思路一:事务

首先要确定的是,两个表的操作是一起的,购买记录多一条,购买次数也要+1,他俩要么都成功,要么都失败。所以这两个表的操作要在一个事务中进行。中途任何一个操作失败,都需要回滚。

//伪代码
	transaction.begin();
	record.insert();
	if (failed) transaction.rollback();
	price.update();
	if (failed) transaction.rollback();
	transaction.commit();

存在的问题:事务本身不能解决并发情境下的数据不一致问题,因为两个事务可以同时begin,也可以同时commit,仍然会有之前说的超卖问题。加上事务,只是保证了两张表之间的操作连续起来,不会出现两个表之间的数据不一致,是解决并发带来问题的第一步。

思路二:表锁

因为涉及对表字段的更新,所以考虑对price表加表锁。当一个事务在对其中某条记录进行更新时,别的事务不能写这张表。等于是将并发事务变成了串行的,可以彻底解决并发问题。

存在的问题:表锁的开销太大,效率太低。如果并发量变大,那么等待释放表锁的时间会很长。

思路三:行锁

只对涉及的某一行进行加锁,更新操作。这样可以避免因为锁表带来的性能下降问题。

存在的问题:锁行的方式,由于访问行顺序不同,有可能产生互相等待的死锁。
解决方法:按照id的升序进行加行锁。

思路四:redis锁

redis锁在大量并发的情况下,可以提高访问数据库的效率。要根据业务场景考虑是否有必要加redis锁。
注意并发和高并发之间的量级区别。

同类型文章:
高并发场景下的解决方案以及分布式锁的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值