springboot分布式锁的redis简易实现

准备环境:

1、jdk

2、mysql

3、redis

4、idea

5、postman

 

项目源码:

链接:https://pan.baidu.com/s/17epRS84-MxXYnj8wESyypQ 
提取码:m8ie

 

实现的原理主要是在redis中记录某个Key来记录该业务是否正在被其他线程所占用

 

  1. 工程目录

这里主要贴一下RedisLock和GoodsService

package com.test.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.test.config.RedisLock;
import com.test.entity.Goods;
import com.test.mapper.GoodsMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;

@Service
public class GoodsService extends ServiceImpl<GoodsMapper, Goods> {

    private final static Logger logger = LoggerFactory.getLogger(GoodsService.class);

    @Autowired
    private RedisLock redisLock;
    /**
     * 超时时间 5s
     */
    private static final int TIMEOUT = 5 * 1000;

    public String updateNumById(Integer id, String code, Integer count) {
//        上锁
        long time = System.currentTimeMillis() + TIMEOUT;

        if (!redisLock.lock(code, String.valueOf(time))) {
            return "排队人数太多,请稍后再试.";
        }

        try {
            Goods goods = getById(id);
            if (goods != null) {
                if (goods.getNum() <= 0) {
                    return "商品卖完了";
                }
                if (goods.getNum() < count) {
                    return "商品卖完了,剩余数量:" + goods.getNum() + " 你购买数量:" + count;
                }

                System.out.println("剩下多少:" + goods.getNum());
                System.out.println("减少多少:" + count);

                goods.setNum(goods.getNum() - count);
                baseMapper.updateById(goods);

                return "购买成功";
            } else {
                return "商品不存在";
            }

        } finally {
//            解锁
            redisLock.release(code, String.valueOf(time));


        }


    }

    @Override
    public Goods getById(Serializable id) {
        return baseMapper.selectById(id);
    }
}
package com.test.config;


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

@Component
public class RedisLock {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 加锁
     *
     * @param code      加锁的Key
     * @param timeStamp 时间戳:当前时间+超时时间
     * @return
     */
    public boolean lock(String code, String timeStamp) {
        if (stringRedisTemplate.opsForValue().setIfAbsent(code, timeStamp)) {
//            如果key不存在,上锁成功
            return true;
        }
//        上锁失败
//        判断是否超时
        String lock = stringRedisTemplate.opsForValue().get(code);
        if (!StringUtils.isEmpty(lock) && Long.parseLong(lock) < System.currentTimeMillis()) {
//          锁已经存在,这里代表已经存在的锁
            String preLock = stringRedisTemplate.opsForValue().getAndSet(code, timeStamp);
//          这个操作为了获取锁的同时,更新时间戳,万一同时有两个线程来到这里,确保timeStamp是唯一的
            if (!StringUtils.isEmpty(preLock) && preLock.equals(lock)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 释放锁
     *
     * @param code
     * @param timeStamp
     */
    public void release(String code, String timeStamp) {
        try {
            String currentValue = stringRedisTemplate.opsForValue().get(code);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(timeStamp)) {
                stringRedisTemplate.opsForValue().getOperations().delete(code);
            }
        } catch (Exception e) {
            System.out.println("解锁异常");
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值