分布式锁Mysql篇
分布式锁
CREATE TABLE `stock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_code` varchar(20) NOT NULL,
`warehouse` varchar(20) NOT NULL,
`count` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_pc` (`product_code`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
1.JVM本地锁
2.一个sql
3.悲观锁:select ...from update
mysql悲观锁中使用行级锁:
1.锁的查询或者更新条件必须是索引字段
2.查询或者更新条件必须是具体值 不能使用 like这样的模糊查询
Mapper代码实现:
@select("select * from stock where product_code = #{productCode} for update;")
List<Stock> queryStock(String productCode);
service实现:
解决了锁定的范围 同时一个商品的多条库存记录 记录了库存变化前后的状态
缺点问题:
1.性能问题 性能较低
2.会产生死锁: 对多条数据加锁时,加锁的顺序要一致
3.库存操作要统一:用select ...for update 而用普通select锁不住
4.mysql的乐观锁:时间戳version版本号CAS机制
CREATE TABLE `stock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_code` varchar(20) NOT NULL,
`warehouse` varchar(20) NOT NULL,
`count` int(11) NOT NULL,
`version` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_pc` (`product_code`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
如果version与mysql中的不相等就更新失败 再次进行尝试!
servic实现:
会出现栈溢出 还有超时问题!
解决栈溢出问题
MDL 更新删除操作 会进行加锁 就会出现超时问题
去掉手动事务@Transactional(事务也会加锁) 后面当进行到 if(this....update...)时候 本来有悲观锁 当执行失败的就会放掉锁 后面就不会阻塞
最终:
乐观锁存在的问题:
1.高并发的情况下,性能极低。 (乐观锁适合读多写少的情况)
2.CAS会产生ABA问题。
3.读写分离的情况下导致乐观锁不可靠
myqsl锁总结:
性能:一个sql>悲观锁>JVM锁>乐观锁
如果追求极致的性能,业务场景简单并不需要记录前后变化的情况下 优先选择:一个sql;
如果写并发量低(读多),争抢不是很激烈的情况下 优先选择:乐观锁;
如果写并发量较高,一般会经常冲突,此时选择乐观锁的话,会导致业务代码间的不断重试。 应该优先选择:悲观锁;
不推荐使用JVM本地锁;