Spring Boot实现分布式锁的自动释放的示例代码
作者:程序媛徐师姐 发布时间:2023-10-17 11:06:24
Spring Boot如何实现分布式锁的自动释放
在分布式系统中,为了保证数据的一致性和可靠性,常常需要使用分布式锁。在实际开发中,我们可以使用 Redis、Zookeeper 等分布式系统来实现分布式锁。本文将介绍如何使用 Spring Boot 来实现分布式锁的自动释放。
1. Redis 实现分布式锁
Redis 是一个开源的内存数据存储,常用于缓存、消息队列和分布式锁等场景。下面是使用 Redis 实现分布式锁的示例代码:
@Service
public class RedisLockService {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
Boolean success = connection.setNX(key.getBytes(), value.getBytes());
if (success) {
connection.expire(key.getBytes(), expireTime);
}
return success;
});
return result != null && result;
}
public void releaseLock(String key, String value) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
byte[] key## 1. Redis 实现分布式锁
Redis 是一个开源的内存数据存储,常用于缓存、消息队列和分布式锁等场景。下面是使用 Redis 实现分布式锁的示例代码:
```java
@Service
public class RedisLockService {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
Boolean success = connection.setNX(key.getBytes(), value.getBytes());
if (success) {
connection.expire(key.getBytes(), expireTime);
}
return success;
});
return result != null && result;
}
public void releaseLock(String key, String value) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
byte[] keyBytes = key.getBytes();
byte[] valueBytes = value.getBytes();
byte[] currentValueBytes = connection.get(keyBytes);
if (Arrays.equals(valueBytes, currentValueBytes)) {
connection.del(keyBytes);
}
return null;
});
}
}
在上述代码中,tryLock
方法使用 Redis 的 setNX
命令来尝试获取锁。如果成功获取锁,则使用 expire
命令来设置锁的过期时间。releaseLock
方法则使用 Redis 的 get
、del
命令来判断锁是否属于当前线程,如果是则释放锁。
使用 Redis 实现分布式锁的过程比较简单,但是需要注意以下几点:
锁的 key 必须唯一,最好使用带有业务含义的字符串作为 key。
锁的 value 必须保证唯一性,可以使用 UUID 等随机字符串来生成。
在释放锁的时候,需要判断锁是否属于当前线程,否则可能会释放其他线程的锁。
2. 基于 AOP 实现自动释放锁
使用 Redis 实现分布式锁的过程相对简单,但是在实际使用中,我们往往需要在获取锁的同时自动释放锁,避免出现死锁等问题。下面是使用 AOP 实现自动释放锁的示例代码:
@Aspect
@Component
public class RedisLockAspect {
@Autowired
private RedisLockService redisLockService;
@Around("@annotation(redisLock)")
public## 1. Redis 实现分布式锁
Redis 是一个开源的内存数据存储,常用于缓存、消息队列和分布式锁等场景。下面是使用 Redis 实现分布式锁的示例代码:
```java
@Service
public class RedisLockService {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
Boolean success = connection.setNX(key.getBytes(), value.getBytes());
if (success) {
connection.expire(key.getBytes(), expireTime);
}
return success;
});
return result != null && result;
}
public void releaseLock(String key, String value) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
byte[] keyBytes = key.getBytes();
byte[] valueBytes = value.getBytes();
byte[] currentValueBytes = connection.get(keyBytes);
if (Arrays.equals(valueBytes, currentValueBytes)) {
connection.del(keyBytes);
}
return null;
});
}
}
在上述代码中,tryLock
方法使用 Redis 的 setNX
命令来尝试获取锁。如果成功获取锁,则使用 expire
命令来设置锁的过期时间。releaseLock
方法则使用 Redis 的 get
、del
命令来判断锁是否属于当前线程,如果是则释放锁。
使用 Redis 实现分布式锁的过程比较简单,但是需要注意以下几点:
锁的 key 必须唯一,最好使用带有业务含义的字符串作为 key。
锁的 value 必须保证唯一性,可以使用 UUID 等随机字符串来生成。
在释放锁的时候,需要判断锁是否属于当前线程,否则可能会释放其他线程的锁。
2. 基于 AOP 实现自动释放锁
使用 Redis 实现分布式锁的过程相对简单,但是在实际使用中,我们往往需要在获取锁的同时自动释放锁,避免出现死锁等问题。下面是使用 AOP 实现自动释放锁的示例代码:
@Aspect
@Component
public class RedisLockAspect {
@Autowired
private RedisLockService redisLockService;
@Around("@annotation(redisLock)")
public## 1. Redis 实现分布式锁
Redis 是一个开源的内存数据存储,常用于缓存、消息队列和分布式锁等场景。下面是使用 Redis 实现分布式锁的示例代码:
```java
@Service
public class RedisLockService {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {
Boolean success = connection.setNX(key.getBytes(), value.getBytes());
if (success) {
connection.expire(key.getBytes(), expireTime);
}
return success;
});
return result != null && result;
}
public void releaseLock(String key, String value) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
byte[] keyBytes = key.getBytes();
byte[] valueBytes = value.getBytes();
byte[] currentValueBytes = connection.get(keyBytes);
if (Arrays.equals(valueBytes, currentValueBytes)) {
connection.del(keyBytes);
}
return null;
});
}
}
在上述代码中,tryLock
方法使用 Redis 的 setNX
命令来尝试获取锁。如果成功获取锁,则使用 expire
命令来设置锁的过期时间。releaseLock
方法则使用 Redis 的 get
、del
命令来判断锁是否属于当前线程,如果是则释放锁。
使用 Redis 实现分布式锁的过程比较简单,但是需要注意以下几点:
锁的 key 必须唯一,最好使用带有业务含义的字符串作为 key。
锁的 value 必须保证唯一性,可以使用 UUID 等随机字符串来生成。
在释放锁的时候,需要判断锁是否属于当前线程,否则可能会释放其他线程的锁。
2. 基于 AOP 实现自动释放锁
使用 Redis 实现分布式锁的过程相对简单,但是在实际使用中,我们往往需要在获取锁的同时自动释放锁,避免出现死锁等问题。下面是使用AOP 实现自动释放锁的示例代码:
@Aspect
@Component
public class RedisLockAspect {
@Autowired
private RedisLockService redisLockService;
@Around("@annotation(redisLock)")
public Object doAround(ProceedingJoinPoint joinPoint, RedisLock redisLock) throws Throwable {
String lockKey = redisLock.key();
String lockValue = UUID.randomUUID().toString();
long expireTime = redisLock.expireTime();
boolean locked = redisLockService.tryLock(lockKey, lockValue, expireTime);
if (!locked) {
throw new RuntimeException("获取分布式锁失败");
}
try {
return joinPoint.proceed();
} finally {
redisLockService.releaseLock(lockKey, lockValue);
}
}
}
在上述代码中,@Around
注解表示在方法执行前后执行该方法,@annotation(redisLock)
表示只有标注了 @RedisLock
注解的方法才会执行该方法。在方法执行前获取分布式锁,如果获取失败则抛出异常,否则执行方法;在方法执行后释放分布式锁。
使用 AOP 实现自动释放锁的过程比较简单,但是需要注意以下几点:
使用 AOP 实现自动释放锁的前提是获取锁的操作必须是同步的,即同一个锁只能被一个线程获取。如果不同步,可能会导致多个线程同时获取到锁,但只有一个线程能够释放锁,其他线程会一直等待。
在使用 AOP 实现自动释放锁时,需要注意异常处理。如果方法执行抛出异常,分布式锁不会被释放,可能会导致死锁等问题。因此,需要在
finally
块中释放分布式锁,确保锁的释放操作一定会被执行。使用 AOP 实现自动释放锁会在每次方法执行前后都进行锁的获取和释放操作,可能会对系统性能产生一定的影响。因此,在高并发场景下,需要考虑使用其他方式实现自动释放锁,例如使用定时任务等方式。
3. 总结
使用 Spring Boot 实现分布式锁可以保证在分布式系统中数据的一致性和可靠性。本文介绍了使用 Redis 实现分布式锁的示例代码,以及使用 AOP 实现自动释放锁的示例代码。在实际使用中,需要注意锁的 key 和 value 的唯一性,以及锁的释放操作是否正确,避免出现死锁等问题。同时,需要根据具体场景选择合适的方式实现自动释放锁,确保系统性能和稳定性。
来源:https://blog.csdn.net/2301_77835649/article/details/130993596


猜你喜欢
- 前言前两篇我们详细了解了 findById 和 findAll 以及 findAll 的分页查询,如果说JPA只有上面的两种查询功能,那就太
- 本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时
- Android Fragment的回退栈点开之后按一次回退键只返回一次MainActivity 类public class Ma
- 参数校验主要使用两个标签@Validated和@Valid;@Valid是Hibernate的注解校验,@Validated是spring的
- 定义定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。解决的问题在有多种算法相似的情况下,
- 近期遇到了DateTime到底是值类型还是引用类型的疑惑,顺势较深入地了解一下DateTime相关的内容结论:DateTime是值类型,因为
- 本文实例为大家分享了Android实现信息弹出框的具体代码,供大家参考,具体内容如下layout下的dialog_common_layout
- 前言 OFD是国家标准版式文档格式,于2016年生效。OFD文档国家标准参见《电子文件存储与交换格式版式文档》。既然是国家标准,O
- 阅读收获理解SpringBoot自动配置原理一、SpringBoot是什么SpringBoot 的诞生就是为了简化 Spring 中繁琐的
- 如下所示:Ctrl+1或F2快速修复Ctrl+D快捷删除行Shift+Enter 快速切换到下一行,在本行的任何位置都可Ctrl+F11快速
- 本文实例讲述了Spring计划任务用法。分享给大家供大家参考,具体如下:一 点睛从Spring3.1开始,计划任务在Spring中的实现变得
- 类型转换Convert.To类型()1、表达式将变量和字面值(在使用运算符时,他们都称作操作数)与运算符组合起来就得到了表达式,它是计算的基
- web 容器的设计开发一个web容器涉及很多不同方面不同层面的技术,例如通信层的知识,程序语言层面的知识等等,且一个可用的web容器是一个比
- 面试官:请问StringBuffer和StringBuilder有什么区别?这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面
- 前言Android提供了很多种保存应用程序数据的方法。其中一种就是用SharedPreferences对象来保存我们私有的键值(key-va
- 概述现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。J
- 新年了,项目中要作个动画,整体要求实现彩带乱飞,烟花冲天而起,烟花缩放,小鸡换图,小鸡飘移,横幅裁剪、展开等动画效果,全局大量使用了属性动画
- 本文实例展示了C#中this指针的用法,对于初学者进一步牢固掌握C#有很大帮助,具体内容如下:一、this指针是什么:这里有一些面向对象编程
- 迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的。只要拿到这个对象
- 本文实例讲述了C#中DataSet转化为实体集合类的方法,分享给大家供大家参考。具体实现方法如下:/// <summary>//