lua脚本做redis的锁

74 阅读1分钟
package com.wosai.upay.job.biz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import java.util.Arrays;
public class RedisLock {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private final static DefaultRedisScript<Long> LOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2])  else return 0 end"
            , Long.class
    );
    private final static DefaultRedisScript<Long> UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"
            , Long.class
    );
    
    public boolean lock(final String key, final String value, long timeInSeconds) {
        Long result = redisTemplate.execute(LOCK_LUA_SCRIPT, Arrays.asList(key), value, String.valueOf(timeInSeconds));
        return result == 1;
    }
    public boolean unlock(String key, String value) {
        Long result = redisTemplate.execute(UNLOCK_LUA_SCRIPT, Arrays.asList(key), value);
        return result != null && result == 1;
    }
}
if (!redisLock.lock(key, value,”时间“)) {
            return;
        }
        try {
           //做业务
        } catch (Exception e) {
//业务处理
        } finally {
            redisLock.unlock(key, value);
        }

不加过期时间的写法:

public boolean lock(final String key, final String value, long waitTimeMillis, long expireSeconds) throws InterruptedException {
        boolean success = false;
        long alreadyWaitTime = 0;
        while (true) {
            try {
                Long result = 0L;
                if (expireSeconds != 0) {
                    result = redisTemplate.execute(LOCK_LUA_SCRIPT_WITH_EXPIRE, Arrays.asList(key), value, String.valueOf(expireSeconds));
                } else {
                    result = redisTemplate.execute(LOCK_LUA_SCRIPT_NO_EXPIRE, Arrays.asList(key), value, String.valueOf(expireSeconds));
                }
                success = (result == 1);
            } catch (Exception e) {
                log.warn("加锁失败:{}", key, e);
            }
            if (success) {
                return true;
            }
            if (alreadyWaitTime >= waitTimeMillis) {
                return false;
            }
            Thread.sleep(10L);
            alreadyWaitTime = alreadyWaitTime + 10;
        }
    }
    public boolean unlock(String key, String value) {
        Long result = redisTemplate.execute(UNLOCK_LUA_SCRIPT, Arrays.asList(key), value);
        return result != null && result == 1;
    }
    private final static DefaultRedisScript<Long> LOCK_LUA_SCRIPT_WITH_EXPIRE = new DefaultRedisScript<>(
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2])  else return 0 end"
            , Long.class
    );
    private final static DefaultRedisScript<Long> LOCK_LUA_SCRIPT_NO_EXPIRE = new DefaultRedisScript<>(
            "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then return 1 else return 0 end"
            , Long.class
    );
    private final static DefaultRedisScript<Long> UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"
            , Long.class
    );

参考:RedisTemplate下Redis分布式锁引发的系列问题_redistemplate加锁其它写入有影响吗-CSDN博客

Redis分布式锁的实现方式(redis面试题)_Redis_脚本之家

redis分布式锁及会出现的问题解决_Redis_脚本之家