Java超卖问题
超卖问题是指并发环境下 对于一些库存操作,减少的库存比实际库存多的问题
解决方法
一.数据库排它锁
这是最简单的,也是性能最差的,先查询 查询的时候加排它锁,然后更新数据 库存--;
这样就天然的解决了超卖问题,但是显而易见的 这样有很多缺点
1.性能太差,几乎是牺牲了并发性能
2.容易造成死锁
3.若是库存设计多个服务,无法跨库加锁
只适用于单机或需要保持强一致的场所
二、数据库乐观锁(CAS)
先查询
再用cas的方式更新数据(update where id=? and version=?")
这样不用加互斥锁 性能会好一些
但是需要重试机制,比较消耗cpu,而且若是并发量高 会造成大量重试
三、Redis+lua脚本
操作缓存,而不直接操作数据库
本来在高并发场景下,库存信息就要放在redis中 不可能放到数据库 每次都从数据库查
用lua脚本
第一步
查询库存余量 若为0则放弃
第二步
将库存容量-1 放回redis中
那怎么更新mysql呢?
一般通过消息队列异步地更新:一定要添加重试策略(要实现幂等性)避免更新失败,若就是失败了则要持久化这一次任务,服务上线时插队执行任务
需要容忍数据的最终一致性!
四、分布式锁
解决分布式集群下的超卖问题 用Redission
扣库存前加锁 保证只有一个线程能拿到锁
其他
其他的方法还有令牌桶这样的限流思路,就是假设库存为10000,只发10000个令牌,这样就不会超卖了(但是会不会少卖呢?)