三大种
1)基于数据库
https://blog.csdn.net/tianjiabin123/article/details/72625156
通过数据库的排他锁来实现分布式锁。 基于MySQL的InnoDB引擎,可以使用以下方法来实现加锁操作:
创建一个数据库是基于InnoDB引擎
CREATE TABLE methodLock
(
id
int(11) NOT NULL AUTO_INCREMENT COMMENT ‘主键’,
method_name
varchar(64) NOT NULL DEFAULT ‘’ COMMENT ‘锁定的方法名’,
desc
varchar(1024) NOT NULL DEFAULT ‘备注信息’,
update_time
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ‘保存数据时间,自动生成’,
PRIMARY KEY (id
),
UNIQUE KEY uidx_method_name
(method_name
) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘锁定中的方法’;
然后我们就可以通过显式的调用排他锁来实现独占
- public boolean lock(){
-
connection.setAutoCommit(false)
-
while(true){
-
try{
-
result = select * from methodLock where method_name=xxx for update;
-
if(result==null){
-
return true;
-
}
-
}catch(Exception e){
-
}
-
sleep(1000);
-
}
-
return false;
- }
Select * from table for update会显式的加独占行锁,这样改行就再被加锁了。我们可以认为获取了排他锁的线程就可以获取分布式锁,然后去执行响应的业务逻辑。执行完毕后,再提交事务以解锁。
1.
public void unlock(){
2. connection.commit();
3. }
但是需要注意的是,InnoDB引擎在加行级锁的时候,是锁在索引上的,如果不是通过索引项去查找那么久不会使用行锁,而是使用表锁。所以我们在建表时方法名是添加了索引的。同时,这个锁应当是唯一索引,对于存在重载方案的建议把参数类型也加上,这样保证了唯一。
上述是一种悲观锁
这个mysql加锁的方式的缺点是:数据库单点问题,以及如何重入(获取独占锁失败后会一直阻塞直到成功,这个无法控制,不仅仅是无法重入,还会产生占用数据库连接的问题)。所以这种方式很少使用,一般只在非常少量并发请求时才使用。
还可以实现乐观锁。就是只有当数据是什么状态时才会去做什么操作,类似CAS
a)先查出数据
select id, resource, state,version from t_resource where state=1 and id=5780;
b)做更新操作
update t_resoure set state=2, version=27, update_time=now() where resource=xxxxxx and state=1 and version=26
c. 如果上述update语句真正更新影响到了一行数据,那就说明占位成功。如果没有更新影响到一行数据,则说明这个资源已经被别人占位了。
它类似于CAS,故也存在ABA问题。
2)基于redis等内存数据库
具体讲redis材料,可能存在一定的缺陷,可以考虑用redLock
3)基于zk
具体见上,可靠性最高,但是性能不是特别高,而且比较复杂