【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁

spring boot基于redis的LUA脚本 实现分布式锁【都是基于redis单点下】

一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁

1.pom.xml

<!-- Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2.RedisLock 工具类 (注入spring)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import java.util.Collections;


/**
 *  spring boot 1.5.X
 * 使用redis 的 lua脚本  基于单点实现分布式锁
 *
 * lua脚本作为原子性操作,保证加锁和设置超时时间 为原子性操作
 * @author sxd
 * @date 2019/5/27 10:52
 */
@Component
public class RedisLock {

    @Autowired
    RedisTemplate redisTemplate;

    private static final Long SUCCESS = 1L;

    /**
     * 获取锁
     *
     * @param lockKey       redis的key
     * @param value         redis的value要求是随机串,防止释放其他请求的锁
     * @param expireTime    redis的key 的过期时间  防止死锁,导致其他请求无法正常执行业务
     * @return
     */
    public  boolean lock(String lockKey, String value, int expireTime) {

        String script = "if redis.call('setNx',KEYS[1],ARGV[1])  then " +
                "   if redis.call('get',KEYS[1])==ARGV[1] then " +
                "      return redis.call('expire',KEYS[1],ARGV[2]) " +
                "   else " +
                "      return 0 " +
                "   end " +
                "end";

        RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);

        //对非string类型的序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value, String.valueOf(expireTime));

        return SUCCESS.equals(result);

    }

    /**
     * 释放锁
     *
     * @param lockKey   redis的key
     * @param value     redis的value  只有value比对一致,才能确定是本请求 加的锁 才能正常释放
     * @return
     */
    public  boolean unlock(String lockKey, String value) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);

        try {
            Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value);
            if (SUCCESS.equals(result)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

}
View Code

3.controller使用

/**
     * 使用分布式锁 逻辑
     * 1.准备好 key  value  expireTime
     * value要求是随机字符串
     * expireTime 是根据业务 衡量决定的 锁过期时间
     *
     * 2.获取锁
     * 成功获取,则执行业务,执行完成,释放锁
     * 失败获取,则重试获取,注意获取锁的时间间隔,直到获取成功,执行业务,最后释放锁
     *
     * 注意:
     *     对于redis加锁的业务,尽量用在耗时短的业务上。
     *
     */
    @RequestMapping("/test")
    public void test(){
        boolean flag = false; //标识  是否正常获取锁
        String uuid = UUID.randomUUID().toString(); //redis的value  是一串随机数
        flag = lock.lock("mykey1",uuid,5);
        if (flag){
            business(uuid);
        }else {

            //如果未正常获取锁  可以通过重试 直到获取锁成功
            while (!flag){
                try {

                    //重试 时间间隔  减少与redis交互次数
                    Thread.sleep(3000);
                    System.out.println("重试");
                    flag = lock.lock("mykey1",uuid,5);
                    if (flag){
                        business(uuid);
                    }else {
                        continue;
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public void business(String uuid){
        
        try {
            System.out.println("加锁成功,执行业务");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //业务执行完成  正常释放锁
            lock.unlock("mykey1",uuid);
        }
    }
View Code

二.spring boot 2.x 基于redis 的LUA脚本 实现分布式锁

1.

猜你喜欢

转载自www.cnblogs.com/sxdcgaq8080/p/10931246.html