分布式锁的几种实现方式
DB
并发下的问题:
丢失更新:一个事务的更新覆盖了其它事务的更新结果。A把值从6改为2,B把值从6改为3。A的更新结果丢失。
脏读:一个事务读取其它完成一半事务的记录时,就会发生脏读取。A、B读到值都为6,B把值改为2,A认为的值仍为6。
悲观锁
1select * from table where id = 1 for update;//行级锁 要有明确的主键1select * from table for update;//表级锁注:此时只有执行完了for update操作,即该事务commit后,其他select for update、update操作才会执行,但单纯的select操作完全可以执行。
乐观锁
使用版本号或者时间戳。
12select x1,x2 ... ,version from table where x1 = 1;update table set version = version + 1 where x1 = 1 and version = ?乐观锁不能解决脏读的问题。
注:效率低下,只能根据业务场景适量选择。
需要客户端不断重试获取锁。
Redis
4个命令:setnx get getset del
|
|
注:timeout 的值应根据业务来设,因为当业务逻辑执行时间过长,比timeout长时,依然存在并发问题;
这几个命令在redis集群下情况将很复杂,将会有问题;
需要客户端不断重试获取锁。
ZooKeeper
求最小节点
|
|
注:可靠性最好,实现最简单的方式。但是需要额外维护成本,依业务场景选择;
通过服务器端通知客户端锁被释放。