redis的hmset乐观锁的实现
1.lua脚本(集成实现了乐观锁,hmset ,expire等)
local key=KEYS[1];
local oldVerion=tonumber(ARGV[1]);
local seconds=ARGV[2];
local fieldLen = table.getn(ARGV)-2;
local idx=1;
local argvIdx=1;
local version = redis.call('HINCRBY',key,'version','0');
if(version~=oldVerion) then
return 0;
end
for idx=1,fieldLen,2 do
argvIdx=idx+2;
redis.call('HSet',key,ARGV[argvIdx],ARGV[argvIdx+1]);
end
version =redis.call('HINCRBY',key,'version','1');
redis.call('EXPIRE',key,seconds);
return version;
2.eval直接调用测试
传入参数
keysCount: 1
key: key11
version: 0
ttl: 6000
field1: icbc
field2:wh
eval "local key=KEYS[1];local oldVerion=tonumber(ARGV[1]);local seconds=ARGV[2];local fieldLen = table.getn(ARGV)-2;local idx=1;local argvIdx=1;local version = redis.call('HINCRBY',key,'version','0');if(version~=oldVerion) then return 0; end for idx=1,fieldLen,2 do argvIdx=(idx-1)+1+2; redis.call('HSet',key,ARGV[argvIdx],ARGV[argvIdx+1]); end version =redis.call('HINCRBY',key,'version','1');redis.call('EXPIRE',key,seconds);return version;" 1 key11 0 6000 field1 icbc field2 wh
3.java代码
@Autowired
private StringRedisTemplate redisTemplate; private static final String LUA_SCRIPT_HMSETBYVERSION = "local key=KEYS[1];\n" +
"local oldVerion=tonumber(ARGV[1]);\n" +
"local seconds=ARGV[2];\n" +
"local fieldLen = table.getn(ARGV)-2;\n" +
"local idx=1;\n" +
"local argvIdx=1;\n" +
"local version = redis.call('HINCRBY',key,'version','0');\n" +
"if(version~=oldVerion) then\n" +
"\treturn 0;\n" +
"end\n" +
"for idx=1,fieldLen,2 do \n" +
"argvIdx=idx+2;\n" +
"redis.call('HSet',key,ARGV[argvIdx],ARGV[argvIdx+1]);\n" +
"end \n" +
"version =redis.call('HINCRBY',key,'version','1');\n" +
"redis.call('EXPIRE',key,seconds);\n" +
"return version;";
private static final String LUA_SCRIPT_HMSETBYVERSION_SHA1 = SHA1.encode(LUA_SCRIPT_HMSETBYVERSION);
public long compareAndHMset(String key, int version, Map<String, String> values, int seconds) {
if (CollectionUtils.isEmpty(values)) {
return 0;
} List<String> keys = Collections.singletonList(key);
List<String> argvs = new ArrayList<>(values.size() * 3); argvs.add(Integer.toString(version));
argvs.add(Integer.toString(seconds)); for (Map.Entry<String, String> item : values.entrySet()) {
argvs.add(item.getKey());
argvs.add(Strings.isNullOrEmpty(item.getValue()) ? "" : item.getValue());
} Long result = redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
// 集群模式和单点模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
// 集群
if (nativeConnection instanceof JedisCluster) {
try {
return (Long) ((JedisCluster) nativeConnection).evalsha(LUA_SCRIPT_HMSETBYVERSION_SHA1,
keys,
argvs);
} catch (redis.clients.jedis.exceptions.JedisNoScriptException ex) {
return (Long) ((JedisCluster) nativeConnection).eval(LUA_SCRIPT_HMSETBYVERSION, keys, argvs);
} catch (Exception ex) {
return 0L;
}
} else {
// 单点 或 哨兵
try {
return (Long) ((Jedis) nativeConnection).evalsha(LUA_SCRIPT_HMSETBYVERSION_SHA1,
keys,
argvs);
} catch (redis.clients.jedis.exceptions.JedisNoScriptException ex) {
return (Long) ((Jedis) nativeConnection).eval(LUA_SCRIPT_HMSETBYVERSION, keys, argvs);
} catch (Exception ex) {
return 0L;
}
}
}
}); return result;
}
4.调用
return 0 < compareAndHMset("hashkey11",
1,
ImmutableMap.of("field1", "icbc2"),
6000
);
redis的hmset乐观锁的实现的更多相关文章
- php+redis 学习 三 乐观锁
<?php header('content-type:text/html;chaeset=utf-8'); /** * redis实战 * * 实现乐观锁机制 * * @example php ...
- redis事务和乐观锁
1 MULTI/EXEC 执行本事务. MULTI set foo bar get foo set foo hello EXEC 在EXEC执行前,三条命令都放入队列中,然后EXEC触发执行.没有回滚 ...
- Redis分布式锁----乐观锁的实现,以秒杀系统为例
本文使用redis来实现乐观锁,并以秒杀系统为实例来讲解整个过程. 乐观锁 大多数是基于数据版本(version)的记录机制实现的.即为数据增加一个版本标识,在基于数据库表的版本解决方案中, ...
- 五分钟学会悲观乐观锁-java vs mysql vs redis三种实现
1 悲观锁乐观锁简介 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果 ...
- redis中使用 check-and-set 操作实现乐观锁
WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为. 被 WATCH 的键会被监视,并会发觉这些键是否被改动过了. 如果有至少一个被监视的键在 EXEC 执行之前 ...
- redis 乐观锁实践秒杀
需求:有一个标(理解成抢红包也行,accountBalance预赋值1000元),大家可以抢购,每个用户抢购成功后,更新最后标的总数,在并发情况下,使用redis的乐观锁,保证更新标总值正确性,先往r ...
- 基于redis的乐观锁实践
redis真是一个分布式应用场景下的好东西,对于我们的应用设计,功劳大大的! 今天要研究的是基于redis的事务机制以及watch指令(CAS)实现乐观锁的过程. 所谓乐观锁,就是利用版本号比较机制, ...
- redis的高级事务CAS(乐观锁)
Optimistic locking using check-and-set(乐观锁) 乐观锁介绍:watch指令在redis事物中提供了CAS的行为.为了检测被watch的keys在是否有多个cli ...
- redis乐观锁(适用于秒杀系统)
redis事务中的WATCH命令和基于CAS的乐观锁 在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能.假设我们通过WATCH命令在事务执行之前监控了多个Key ...
随机推荐
- 装饰器模式-Decerator
一.定义 装饰器模式又叫做包装模式(Wrapper).装饰器模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 在以下情况下应该使用装饰器模式: 1.需要扩展一个类的功能,或给一个类增 ...
- Java+Maven的工程运行Sonar的方式
step 1:在maven->setting.xml中进行配置 修改mvn工程所用的setting.xml文件,在<profiles></profiles>节点中增加: ...
- @property属性装饰器
顾名思义,@property就是一个跟属性相关的装饰器, 使用了它之后,取值和赋值操作都变得简洁 from datetime import date, datetime class User: def ...
- 阿里云吴天议:云原生SDWAN 应用 构建智能化云原生SDWAN生态
2019年11月16日 SDWAN 大会在北京正式召开.阿里云网络资深产品专家吴天议先生继阿里云网络研究员祝顺民先生发表了对云原生SDWAN的进化与展望之后(原文请见https://bit.ly/2K ...
- Prime算法 与 Kruskal算法求最小生成树模板
算法原理参考链接 ==> UESTC算法讲堂——最小生成树 关于两种算法的复杂度分析 ==> http://blog.csdn.net/haskei/article/details/531 ...
- (转)运行pip报错:Fatal error in launcher: Unable to create process using '"'
转:https://blog.csdn.net/cjeric/article/details/73518782 在新环境上安装python的时候又再次遇到了这个情况,这次留意了一下,发现原来的文章有错 ...
- 北风设计模式课程---状态模式State(对象行为型)
北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...
- p5339 [TJOI2019]唱、跳、rap和篮球
分析 代码 #include<bits/stdc++.h> using namespace std; #define int long long ; ; ],inv[],G,cc[][] ...
- nginxUbuntu安装Nginx和正确卸载Nginx Nginx相关 与Nginx报错:nginx: [error] invalid PID number "" in "/run/nginx.pid" 解决方法
https://www.cnblogs.com/zhaoyingjie/p/6840616.html https://blog.csdn.net/adley_app/article/details/7 ...
- mongo可视化工具adminMongo安装
git环境搭建下载地址:https://git-scm.com/downloads 此处,安装环境为windows操作系统,所以选择windows版本下载一直下一步,直至安装完成找到安装git的目录下 ...