zoukankan      html  css  js  c++  java
  • 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];
    " +
                "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;";
        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
            );
  • 相关阅读:
    Django框架---- 自定义分页组件
    Django框架----Form组件补充
    ARM体系的异常中断
    ARM处理机模式--内部寄存器
    产品概述
    简单应用程序的设计 -重复前缀
    简单应用程序的设计字符串处理
    基本输入输出系统BIOS---显示输出
    基本输入输出系统BIOS---键盘输入
    中断
  • 原文地址:https://www.cnblogs.com/zhshlimi/p/11973048.html
Copyright © 2011-2022 走看看