Lua脚本实现setnx命令

/**
 * @author Linging
 * @version 1.0.0
 * @since 1.0
 */
@Component
public class RedisUtil {
    
    

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 基于lua脚本实现setnx+expire原子性
     * 使用set命令
     * @param key
     * @param value
     * @param seconds
     * @return
     */
    public Object setnx(String key, String value, Integer seconds){
    
    
        String script =
                " if redis.call('get', KEYS[1]) " +
                " then return 0; " +
                " else " +
                " redis.call('set', KEYS[1], ARGV[1]) " +
                " redis.call('expire', KEYS[1], ARGV[2]) " +
                " return 1; " +
                " end; ";

        DefaultRedisScript redisScript = new DefaultRedisScript(script, String.class);
        //指定传递参数序列化方式,参数序列化要支持数字,否则报错
        RedisSerializer argsSerializer = new GenericToStringSerializer<>(Object.class);
        //指定返回结果序列化方式
        RedisSerializer<String> resultSerializer = redisTemplate.getDefaultSerializer();

        Object execute = redisTemplate.execute(redisScript,argsSerializer, resultSerializer, Lists.newArrayList(key), value, seconds);
        return execute;
    }


    /**
     * 基于lua脚本实现setnx+expire原子性
     * 使用setnx命令
     * @param key
     * @param value
     * @param seconds
     * @return
     */
    public Object setnx2(String key, String value, Integer seconds){
    
    
        String script =
                " if redis.call('setnx', KEYS[1], ARGV[1]) == 1 " +
                " then " +
                " redis.call('expire', KEYS[1],ARGV[2]) " +
                " return 1 " +
                " else " +
                " return 0 " +
                " end; ";

        DefaultRedisScript redisScript = new DefaultRedisScript(script, String.class);
        //指定传递参数序列化方式
        RedisSerializer argsSerializer = new GenericToStringSerializer<>(Object.class);
        //指定返回结果序列化方式
        RedisSerializer<String> resultSerializer = redisTemplate.getDefaultSerializer();

        Object execute = redisTemplate.execute(redisScript,argsSerializer, resultSerializer, Lists.newArrayList(key), value, seconds);
        return execute;
    }

}

redis序列化方式对于value的处理区别:

1.GenericJackson2JsonRedisSerializer、Jackson2JsonRedisSerializer是先将对象转为json,然后再保存到redis,所以,1在redis中是字符串1,所以无法进行加1。

2.JdkSerializationRedisSerializer使用的jdk对象序列化,序列化后的值有类信息、版本号等,所以是一个包含很多字母的字符串,所以根本无法加1。

3.GenericToStringSerializer、StringRedisSerializer将字符串的值直接转为字节数组,所以保存到redis中是数字,所以可以进行加1

set扩展命令:
Redis在 2.6.12 版本开始,为 SET 命令增加一系列选项:

SET key value[EX seconds][PX milliseconds][NX|XX]

  • EX seconds: 设定过期时间,单位为秒
  • PX milliseconds: 设定过期时间,单位为毫秒
  • NX: 仅当key不存在时设置值
  • XX: 仅当key存在时设置值
    set命令的nx选项,就等同于setnx命令,代码过程如下:
jedis.set(key, value, "NX", "EX", seconds)

猜你喜欢

转载自blog.csdn.net/Linging_24/article/details/126316355