分布式锁产生的缘由是:当多个客户端要同时并发操做数据库时,可能查出来的数据是相同的然后继续写的时候会出现事务方面的问题。如:商品只有一件然后被出售两次,形成数据幻读。html
分布式锁的处理方案有:redis
使用redis操做,数据库
使用zookeeper操做,缓存
数据库方面操做(行锁)并发
以上全部的操做都是至关于在多个客户端之间放一把锁,相似于线程之间争夺锁的过程。分布式
三种方案比较:性能
从理解的难易程度角度(从低到高)线程
数据库 > 缓存 > Zookeepercode
从实现的复杂性角度(从低到高)htm
Zookeeper >= 缓存 > 数据库
从性能角度(从高到低)
缓存 > Zookeeper >= 数据库
从可靠性角度(从高到低)
Zookeeper > 缓存 > 数据库
具体的实现过程是:
1.用redis实现
可使用redis的set(key,1,30,Nx)命令(在redis 2.6以上版本支持),其中的key可使用这些客户端都要操做产品的id号去实现。
那么当解锁时需删除key,删除key要注意避免出现以前线程执行的时间很长致使删除key时删除了后面的客户端key。那么这是要注意设置key-value时必定要将value设置为对应线程的id号然后执行删除对应线程或者客户端的key。
2.用数据库实现
一.基于数据库表
最简单的方式可能就是直接建立一张锁表,当咱们要锁住某个方法或资源时,咱们就在该表中增长一条记录,想要释放锁的时候就删除这条记录。给某字段添加惟一性约束,若是有多个请求同时提交到数据库的话,数据库会保证只有一个操做能够成功,那么咱们就能够认为操做成功的那个线程得到了该方法的锁,能够执行方法体内容。
缺点:会引入数据库单点、无失效时间、不阻塞、不可重入等问题
二.基于数据库的排他锁
若是使用的是MySql的InnoDB引擎,在查询语句后面增长 for update
,数据库会在查询过程当中(须经过惟一索引查询)给数据库表增长排他锁,咱们能够认为得到排它锁的线程便可得到分布式锁,然后能够经过 connection.commit() 操做来释放锁。
会引入数据库单点、不可重入、没法保证必定使用行锁(部分状况下MySQL自动使用表锁而不是行锁)、排他锁长时间不提交致使占用数据库链接等问题。
优势:
直接借助数据库,容易理解。
缺点:
3.使用zookeeper实现
借用大佬的博客:https://www.cnblogs.com/garfieldcgf/p/6380816.html