基于数据库实现分布式锁

作者: 迦叶_金色的人生_荣耀而又辉煌 | 来源:发表于2021-10-09 06:47 被阅读0次

    上一篇 <<<分布式锁的实现方式汇总
    下一篇 >>>基于数据库排他锁实现分布式锁


    要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。
    当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。
    创建这样一张数据库表:

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

    当我们想要锁住某个方法时,执行以下SQL:

    insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)
    

    因为我们对method_name做了唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。
    当方法执行完毕之后,想要释放锁的话,需要执行以下Sql:

    delete from methodLock where method_name ='method_name'
    

    上面这种简单的实现有以下几个问题:

    • 1、这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。
    • 2、这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。
    • 3、这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。
    • 4、这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

    当然,我们也可以有其他方式解决上面的问题。
    数据库是单点?搞两个数据库,数据之前双向同步。一旦挂掉快速切换到备库上。
    没有失效时间?只要做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。
    非阻塞的?搞一个while循环,直到insert成功再返回成功。
    非重入的?在数据库表中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。


    推荐阅读:
    <<<分布式锁的实现方式汇总
    <<<Redis实现分布式锁的原理分析
    <<<Redis分布式锁的实现代码示例
    <<<使用Redisson工具实现分布式锁
    <<<Redis官方提出的redlock分布式锁
    <<<Zookeeper示例之分布式锁
    <<<基于数据库排他锁实现分布式锁
    <<<基于数据库或排他锁实现分布式锁总结

    相关文章

      网友评论

        本文标题:基于数据库实现分布式锁

        本文链接:https://www.haomeiwen.com/subject/tzzmnltx.html