美文网首页程序员
springboot实现redis分布式锁

springboot实现redis分布式锁

作者: 创奇 | 来源:发表于2020-05-06 17:14 被阅读0次

分布式锁主要用于分布式服务器保证共享资源的访问同步。

实现流程:先获取锁,得到锁可以访问共享资源。如:库存资源。
当前用户访问时先获取锁,才可以访问资源,如:
将抢购的商品id作为key,过期时间作为value,存到redis服务,
当锁没有释放时,其他用户访问同一资源时,获取不了锁则无法访问;
机制:锁未释放,用户访问相同资源,先会尝试获取锁。
获取锁机制:如果锁不存在则设置锁,存在则获取value1(过期时间)
如果未过期则获取锁失败,过期则重新设置锁并获取之前锁的过期时间value2
value1和value2比较相同则获取锁成功,反之失败。*****
过期时间比较是为了防止同时大量用户访问并设置了锁。

package com.gxuwz.spring.demo.common.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * redis分布式锁
 */
@Component
public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 获取锁
     *
     * @param key
     * @param timeStamp 过期时间戳
     * @return
     */
    public boolean lock(String key, String timeStamp){

        // 如果不存在key则设置成功,即获取锁,如果key存在则什么都不做
        if (redisTemplate.opsForValue().setIfAbsent(key, timeStamp)){
            return true;
        }

        String time = redisTemplate.opsForValue().get(key);

        // key存在但过期了
        if (! StringUtils.isEmpty(time) && Long.parseLong(time) < System.currentTimeMillis()){
            // 重新设置key,并获取之前的值
            String beforeTime = redisTemplate.opsForValue().getAndSet(key, timeStamp);

            // 只让当前设置key的线程获得锁
            if (!StringUtils.isEmpty(beforeTime) && beforeTime.equals(time)){

                return true;
            }

        }
        // 获取锁失败
        return false;
    }

    /**
     * 释放锁
     *
     * @param key
     * @param timeStamp
     */
    public void release(String key, String timeStamp){

        String time = redisTemplate.opsForValue().get(key);

        try {
            if (!StringUtils.isEmpty(time) && time.equals(timeStamp)) {
                Boolean delete = redisTemplate.opsForValue().getOperations().delete(key);

                System.out.println("删除标识:" + delete);
            }
        }catch (Exception e){
            e.printStackTrace();

            System.out.println("释放锁失败!");
        }


    }

}

业务层

 @Autowired
    private RedisLock redisLock;

    /**
     * 抢购商品(测试分布式锁)
     * 
     * @param id
     * @param count
     * @return
     */
    @Override
    public String purchase(int id, int count) {
        String key = id + "";

        // 过期时间 = 当前时间戳 + 过期时间(秒)
        long currentTimeMillis = System.currentTimeMillis() + TIMESTAMP;


        // 获取锁
        if(! redisLock.lock(key, String.valueOf(currentTimeMillis))){

            return "对不起!购买人数太多";
        }

        try {

            try{
                // 为了更好的测试多线程同时进行库存扣减,在进行数据更新之后先等1秒,让多个线程同时竞争资源
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }

            Goods goods = repository.getGoodsById(id);

            if (goods == null) { // 不存在该物品
                return "购买物品失败";
            } else if (goods.getCount() < count) {
                return "对不起!库存余额不足";
            }

            int flag = repository.purchase(id, count);
            System.out.println("flag:" + flag);

            return "购买成功!";
        }finally {
            // 释放锁
            redisLock.release(key, String.valueOf(currentTimeMillis));

            System.out.println("释放锁的时间戳:"+ currentTimeMillis);
        }
    }

应用场景:多台服务器访问的共享资源。

相关文章

网友评论

    本文标题:springboot实现redis分布式锁

    本文链接:https://www.haomeiwen.com/subject/snwwghtx.html