基于数据库实现分布式锁

95 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

还记得上文我们介绍了分布式锁的原理吗? 分布式提供了统一能力保证我们单机扩展的危害性。下面我们分别看看如何实现吧

基于数据库实现分布式锁

CREATE TABLE `three_lock` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `t_mutex` varchar(255) NOT NULL COMMENT '业务防key',
  `t_holder_id` varchar(255) NOT NULL COMMENT '锁持有者id',
  `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mutex_index` (`t_mutex`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


  • t_mutex是我们业务key. 也就是加锁的对象 . 比如我们需要对User对象加锁,那么这个对象的userId或者说这个用户的其他附属信息组合而成的一个key作为我们这里的t_mutex . 因为我们设置了t_mutex唯一,所以多个客户端同一个User来请求锁资源,只会有一个User能够成功入坑。t_holder_id很好理解就是我们持有者的ID,我们正常采用的是线程ID。

加锁

insert into distributed_lock(unique_mutex, holder_id) values (‘unique_mutex’, ‘holder_id’); 如果当前sql执行成功代表加锁成功,如果抛出唯一索引异常(DuplicatedKeyException)则代表加锁失败,当前锁已经被其他竞争者获取。

解锁

delete from methodLock where unique_mutex=‘unique_mutex’ and holder_id=‘holder_id’; 解锁很简单,直接删除此条记录即可。

问题

  • 很明显,数据库如果出现网络延迟我们很有可能不能很完美的实现锁的功能。其中一点就是我们不能一直等待下去吧。那我们就需要加一个等待时常。那么我们为了能够实现高可用的锁,那我们就可以采用数据库的高可用。
  • 不知道聪明的你有没有发现,单机版锁又个重要的特性就是可冲入式,如果我们通过上述方案来实现的话,就失去了可冲入式的特性了。解决办法也很简单,我们可以将t_mutex和t_holder_id组合唯一即可。
  • 但是还是会存在一饿问题就是释放的时候出现网络波动导致释放失败,那么就造成了死锁问题了。