近期军事新闻/站长工具seo综合查询烟雨楼
前置要求:
需要实现SpringBoot+redis的基础配置《SpringBoot整合Redis》
通过lua脚本+redis可以实现分布式锁;
加锁原子性:通过redis自身的setnxex命令即可,setIfAbsent(“lockKey”, value, timeOut, TimeUnit);
解锁原子性:通过redis+lua脚本实现;
定义Lua脚本:
在resources
目录下创建lua
目录,并且创建redisLock.lua
文件;
if redis.call('get',KEYS[1]) == ARGV[1] thenredis.call('del', KEYS[1])return '1';
elsereturn '0'
end
Lua脚本配置:
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;@Configuration
public class RedisLuaConfig {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** @return result 返回 1表示,正常,0表示限制访问*/public boolean runLuaScript(String lockKey, String value) {List<String> keyList = Collections.singletonList(lockKey);// 执行脚本 删除锁DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/redisLock.lua")));redisScript.setResultType(String.class);String execute = stringRedisTemplate.execute(redisScript, keyList, value);return "1".equals(execute);}
}
Lock锁配置:
@Component
public class RedisLockServer {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate RedisLuaConfig redisLuaConfig;public boolean setLock(String lockKey, String value, long time, TimeUnit timeUnit) {return stringRedisTemplate.opsForValue().setIfAbsent(lockKey, value, time, timeUnit);}public void deleteLock(String lockKey, String value) {boolean script = redisLuaConfig.runLuaScript(lockKey, value);}
}
逻辑代码实现:
为了验收方便,在controller层进行业务的编写,测试时,通过浏览器频繁刷新进行请求,模拟锁机制的触发;
@RestController
@RequestMapping("/redis")
public class Test {@Resourceprivate RedisLockServer redisLockServer;@RequestMapping(value = "/lock")public String reduceSku() throws Exception {String value = UUID.randomUUID().toString();// value值任意即可,设置自动过期时间为10Sboolean lock = redisLockServer.setLock("key", value, 10, TimeUnit.SECONDS);if (lock) {// 当前key没有锁,加锁成功 执行数据库查询System.out.println("===>>>加锁成功");// 模拟耗时8STimeUnit.SECONDS.sleep(8);// 所以要保证验证value值和验证成功必须满足原子性,通过redis+lua实现redisLockServer.deleteLock("key", value);} else {// 当前key已经存在锁,加锁失败System.out.println("===>>>加锁失败,等待重试...");}return "操作成功";}
}
效果: