redis分布式锁01

偶尔善良 提交于 2021-01-15 02:26:38

在单体项目中,如果要保证程序只有一个线程进入,使用synchronized锁住代码即可,不过在分布式的情况下,synchronized只能锁住本地对象,如果其他的请求进入,synchronized是没有用的,使用redis的分布式锁;

代码:

public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbWithRedisisLock() {
        //1.站分布式锁 redis占坑 //NS 如果设置的值没有的话就创建  成功返回ok  在创建的时候必须创建和设置锁的过期时间一起原子操作,才能万无一失
        String uuid = UUID.randomUUID().toString();
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);

        if (lock) {
            //设置锁的过期时间,不过如果在这里没设置之前就断电了,就麻烦了
//            stringRedisTemplate.expire("lock",300,TimeUnit.SECONDS);
            //站所成功
            Map<String, List<Catelog2Vo>> dataFromDb;
            try {
                dataFromDb = getDataFromDb();
            }finally {
                //如果我们在获取uuid值对比的中间时已经过期,那么这种情况下要  对比+删除 一起原子操作 使用lua脚本
//            stringRedisTemplate.delete("lock"); //释放锁  如果几个锁一起占用,不小心删除其他的锁改怎么办,就要创建uuid值,删除前对比创建的uuid跟获取的是否相等,再删除
                String script ="if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                stringRedisTemplate.execute(new DefaultRedisScript<Integer>(script,Integer.class),Arrays.asList("lock"),uuid);

            }

            return dataFromDb;

        } else {
            //加锁失败重试
            return getCatalogJsonFromDbWithRedisisLock(); //自旋方式  自旋锁也是阻塞锁,必须释放后其他的才能获取锁
        }

    }

在操作分布式的操作简单来说:

原子性加锁 + 业务代码 + 原子性解锁 = 安全分布式代码

1.先试用redis的加锁定时方法

2.判断当前有没有占用到锁,如果没有占用就递归,一直调用自己,占到锁为止

3.业务代码处理完后要释放锁,使用redis原子性操作,一定要放到finally中释放

    释放锁的原子操作使用的是官方提供的lua脚本,一步到位,源码的意思是Arrays.asList("lock")去redis获取对应锁的数据,跟后面的uuid进行再脚本中比对,如果相等就操作redis删除key,否则返回0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!