Redis作Java分布式锁
redis在性能、操作等方面上有着独特的优势。
1. 检查reids版本
因为redis是在2.6版本后才内置了Lua脚本解释器,所以也就是说要用redis执行lua脚本,最基本的要求就是redis版本必须是2.6.0以上。
查看redis版本命令:info
在启动redis客户端后,连接redis客户端,输入命令如下图:
2.编写lua脚本
做分布式锁的lua语句如下,这边选的是最简单的语句:
local key = KEYS[1]
local value = KEYS[2]
local sec = KEYS[3]
local result = redis.call("SET",key, value, "NX", "EX", sec)
if(result) then
return 1
else
return 0;
end
这个lua脚本的意思是传三个值,第一个值是键,第二个值是值,第三个值是过期时间,单位秒。
3.使用DOS窗口让redis客户端调用lua脚本
命令为:redis-cli.exe --eval E:\redis\redisLock.lua testKey testValue 300
(--
前有个空格)
参数 | 解释 |
redis-cli.exe | 调用该服务 |
–eval | 告诉redis客户端进行执行lua脚本 |
E:\redis\redisLock.lua | 这边是我自己的路径,换成你们lua脚本路径 |
testKey、testValue、300 | 这个lua脚本接受的数据,根据你自己编写的lua脚本而定 |
我们可以看到我们设置的redis的结果和我们预期的是一样的。
4.Java整合Redis
先上Java上的代码:
package com.dahantc.iot.util;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.ScriptSource;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;
import com.dahantc.iot.core.util.LogUtil;
@Service
public class LuaRedisLockUtils{
private final static Logger logger = LogUtil.get();
@Autowired
private RedisTemplate redisTemplate;
public Boolean lock(String key, String value, String seconds){
try{
String path = "redis_lock.lua";
ClassPathResource resource = new ClassPathResource(path);
ScriptSource scriptSource = new ResourceScriptSource(resource);
DefaultRedisScript defaultRedisScript = new DefaultRedisScript();
defaultRedisScript.setScriptSource(scriptSource);
//设置返回类型
defaultRedisScript.setResultType(Long.class);
//组装数据
List<Object> keyList = new ArrayList<>();
keyList.add(key);
keyList.add(value);
keyList.add(seconds);
// 第三个参数是无用的,但不能为空,考虑到内存空间,遂作故用
Long result = (Long)redisTemplate.execute(defaultRedisScript, keyList);
return result == 1;
}catch(Exception e){
logger.error("redis分布式锁存在异常,请注意key:{},value:{}, seconds:{}", key, value, seconds);
return false;
}
}
}
该项目过测试,整合是成功。这边不再跑一遍作示范了。
总结:BASE理论面向的是大型高可用可扩展的分布式系统,和我们传统的ACID型事务是背道而驰的。传统ACID事务要求的是强一致性,而分布式系统则是通过牺牲强一致性来换取可用型,允许数据在某较短的时间内不一致,当然分布式系统也是要保证数据的最终一致性。