概述
一、添加工具类
RedisLockUtil.java
package com.example.utils;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
* redis分布式锁
*
* @author user
*
*/
@Component
@Slf4j
public class RedisLockUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 加锁
*
* @param key
* @param value
* @param expireTime
* @param timeUnit
* @return
*/
public boolean lock(String key, String value, int expireTime, TimeUnit timeUnit) {
// key不存在则创建存储key,key存在则返回null
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, value, expireTime, timeUnit);
if (flag == null || flag == false) {
log.info("锁({},{})失败,该锁已存在或加锁失败", key, value);
return false;
} else {
log.info("锁({},{})成功", key, value);
return true;
}
}
/**
* 释放锁
*
* @param key
* @param value
* @return
*/
public boolean unlock(String key, String value) {
// 使用lua脚本保证原子性
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
Long result = (Long) stringRedisTemplate.execute(redisScript, Arrays.asList(key), value);
if (result == null || result == 0) {
log.info("释放锁({},{})失败,该锁不存在或锁已经过期", key, value);
return false;
} else {
log.info("释放锁({},{})成功", key, value);
return true;
}
}
}
说明:
1、这里注入的操作类是StringRedisTemplate,因为自己定义的RedisTemplate设置了redis键值对<K,V>的value序列化方式被设置成了json格式,所以程序set进redis的string类型值,序列化后会带两个引号。在后面执行lua脚本比较keys和argv时会有问题
2、释放锁时用了lua脚本,保证原子性
3、stringRedisTemplate.execute的value参数是String类型,不能传list
4、集群模式下keys只能传一个,否则会报错:CROSSSLOT Keys in request don't hash to the same slot,所有key必须在同一个哈希槽上
Constants.java添加一个前缀
public static final String LOCK_KEY = "lock:";
二、测试类
RedisLockTest.java
package myboot;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.example.base.Constants;
import com.example.myboot.MybootApplication;
import com.example.utils.RedisLockUtil;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MybootApplication.class)
public class RedisLockTest {
@Autowired
RedisLockUtil redisLock;
@Test
public void redisLockTest() {
String key = Constants.LOCK_KEY + "123";
String value = "123";
redisLock.lock(key, value, 3000, TimeUnit.SECONDS);
}
@Test
public void redisUnlockTest() {
String key = Constants.LOCK_KEY + "123";
String value = "123";
redisLock.unlock(key, value);
}
}
参考资料:
https://blog.csdn.net/qq_33591903/article/details/108278059
https://blog.csdn.net/fedorafrog/article/details/112893769
注:最新代码上传至https://github.com/csj50/myboot
最后
以上就是刻苦灰狼为你收集整理的springboot项目创建笔记28 之《redis分布式锁》的全部内容,希望文章能够帮你解决springboot项目创建笔记28 之《redis分布式锁》所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复