5. 常见的分布式锁实现方式

三大种

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=‘锁定中的方法’;

然后我们就可以通过显式的调用排他锁来实现独占

  1. public boolean lock(){
  2.  connection.setAutoCommit(false)
    
  3.  while(true){
    
  4.      try{
    
  5.          result = select * from methodLock where method_name=xxx for update;
    
  6.          if(result==null){
    
  7.              return true;
    
  8.          }
    
  9.      }catch(Exception e){
    
  10.     }
    
  11.     sleep(1000);
    
  12. }
    
  13. return false;
    
  14. }

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
具体见上,可靠性最高,但是性能不是特别高,而且比较复杂

猜你喜欢

转载自blog.csdn.net/xiaohesdu/article/details/87926857