一、常现的分布式锁
分布式锁在如今最常见的有3种实现方式:
1、数据库
2、缓存
3、Zookeeper
二、常现的分布式锁对比
1、实现难易程度(简 -> 难):数据库 -> 缓存 -> Zookeeper
2、性能(低 -> 高):数据库 -> Zookeeper -> 缓存
本次只分析数据库的具体实现,其余2种见后续文章。
三、数据库版实现思路
锁,字面意思就是封闭一个物体,一把锁只能用一把钥匙打开。同理,一个分布式的锁,在同一时间也只能由一个用户。
废话少说,先上表结构:
--锁表 单库单表
CREATE TABLE IF NOT EXISTS t_db_lock(
Findex INT NOT NULL AUTO_INCREMENT COMMENT '主键',
Flock_name VARCHAR(128) NOT NULL COMMENT '锁名key值',
Fdeadline DATETIME NOT NULL COMMENT '锁的过期时间',
Fstatus FINYINT NOT NULL DEFAULT 1 COMMENT '锁的状态,0-已释放,1-未释放',
--主键约束
PRIMARY KEY (Findex),
--唯一约束
UNIQUE KEY uniq_Flock_name(Flock_name)
)ENGINE=INNODB DEFAULT CHARSET=UTF8 COMMENT '锁表-单库单表';
在程序用可以使用如下结构获取锁
public boolean getLock(String lockName, Integer expiretime) {
//开启事务,本程序结合spring事务
锁对象 = select for update; //锁定当前锁(如果不存在,在mysql默认级别为意向锁)
if (锁对象 == null) {
insert 锁; //根据插入返回是否获取锁
} else {
//根据锁的状态和过期时间update锁,成功返回true
}
return false;
}
这个程序有一个致命的错误,在数据库中不存在当前锁名的时候,多线程竞争锁会因为意向锁的问题,导致死锁。
解决方案:
(1)降低数据库隔离级别为 Read Commited,这样的话多个事务不会因为意向锁的原因导致死锁了。
(2)for update的时候可以根据ConcurrentHashMap分段锁的思想设计,提前加入一些锁,根据具体的locaName去hash后取不同的锁。
(3)也可以捕获异常,然后告诉他获取锁失败。
数据库的实现大概思路就是这样了,缓存和ZK以后实现后会补相应的文章。
网友评论