054-Redis分布式锁

在工作过程中,在同时操作数据库的时候,出现了相同数据插入多条的情况,针对这个问题,我能想到可以有如下几种解决方法:


加悲观锁

在方法前加锁(synchronized关键字),或者在方法里面加锁。但考虑到在集群情况下,依然可能存在问题,故没有采用该方案。


唯一约束

可以给数据库的表中的字段加上唯一约束,这样到执行insert语句时,当发现数据库中已经存在该记录,就会抛出异常!但有的DBA规定不能给字段加唯一约束,所以该方案有时候并不可用。


加分布式锁

由于项目中基本都使用了Redis,所以直接用Redis实现分布式锁。命令 

SET  key  value  NX EX max-lock-time 

是一种在 Redis 中实现锁的简单方法。客户端执行以上的命令:

如果服务器返回 OK ,那么这个客户端获得锁。

如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再重试。

设置的过期时间到达之后,锁将自动释放。可以通过以下修改,让这个锁实现更健壮:

不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)。

不使用 DEL 命令来释放锁,而是发送一个 Lua 脚本,这个脚本只在客户端传入的值和键的口令串相匹配时,才对键进行删除。

这两个改动可以防止持有过期锁的客户端误删现有锁的情况出现。以下是一个简单的解锁脚本示例:

这个脚本可以通过 EVAL ...script... 1 resource-name token-value 命令来调用。



下面看一下代码中的获取和解锁方法:

下面的代码执行了获取锁:

上面使用的是springboot的1.5.10版本,connection.set方法返回类型为void,所以判断是否获取锁成功要根据键值判断一次,这种使用方式对值要求每次都不一样,最好是使用通过发号器生成的唯一id。

从2版本开始,connection.set方法返回类型变为 Boolean ,

如果使用redis分布式锁,建议使用springboot2以上的版本。



下面的代码执行了解锁:

可以看到解锁方法正是执行了lua脚本的内容。


2版本例子测试如下:

再次获取锁失败:


解锁:


再次解锁失败:



代码:https://gitee.com/blueses/spring-boot-demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 上帝厌倦了作为上帝的生活,于是他来到人间寻找升往天堂的欲望。他降生在一片富饶的土地上,那片土地叫江南。他出生在一个...
    大贼偷阅读 275评论 0 3
  • 如果你的工作中出现问题,你是如何处理的? 有的人选择不予处理,担心暴漏自己工作中的缺点,抑或多一事,不如少一事,隐...
    白色沙拉阅读 262评论 0 4
  • 晚秋,寒风萧瑟。前日的一场霏霏初雪,染就了山岗、田野、河川,天空瞬间变得白茫茫。雪花静静地飘落,默默无言地...
    近在远方_fcab阅读 230评论 0 0
  • 恩 我真的好爱你 爱到不自私的地步
    韭菜姐阅读 186评论 0 0
  • tomcat作为一个轻量级的应用,在我们日常应用中没法对它进行监控,我在这里介绍一下psi-probe(还是很强大...
    夜神月_LL阅读 4,806评论 1 5

友情链接更多精彩内容