java-redis锁在代码中实际使用

文章介绍了如何利用Redis实现分布式锁(RedisLock)来防止并发操作,特别是在库存扣减场景中。通过RedisTemplate的setIfAbsent方法尝试加锁,并在finally块中确保释放锁,确保同一时间只有一个线程操作库存。当加锁失败时,会重试并延长原有锁的时间,以避免死锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

在项目中我们经常需要进行扣减库存,或者防止并发操作,本文以redis为基础简单实现防止并发。


一、RedisLock工具类

RedisLock工具类

  1. tryLock方法,返回boolean值,如果未true说明之前没有锁,加锁成功,false说明之前的锁还未释放。
  2. unlock方法,删除锁
@Component
public class RedisLock {
    private static final String LOCK_KEY_PREFIX = "LOCK:";
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     *
     * @param key
     * @param second 锁时间
     * @param waitLockSecond 获取锁失败时等待的时间
     * @return
     */
    public  boolean tryLock(String key, int second, int waitLockSecond) {
        long beginTime = System.currentTimeMillis();
        try {
            while(true) {
                Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(buildLockKey(key), key, second, TimeUnit.SECONDS);
                if(Boolean.TRUE.equals(aBoolean)) {
                    return true;
                }
                if(System.currentTimeMillis() > beginTime + waitLockSecond * 1000) {
                    return false;
                }
                // 休眠
                TimeUnit.MILLISECONDS.sleep(250L);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    private static String buildLockKey(String key) {
        return LOCK_KEY_PREFIX + key;
    }
    public void unlock(String key) {
        redisTemplate.delete(buildLockKey(key));
    }
    public void reLock(String key, int second){
        redisTemplate.opsForValue().set(buildLockKey(key), key, second, TimeUnit.SECONDS);
    }
}

二、实际使用

场景:假设现在我们有一个订单需要扣减库存,我们怎么保证同一时间段只有一个线程操作一个库存呢?
使用redisLock.tryLock来尝试获取锁,获取成功后处理业务逻辑,业务不管成功失败都得在finally 释放锁
redisLock.tryLock方法是单线程的所有不存在多线程加锁成功的现象,有效的防止并发

    @Resource
    private RedisTemplate<String, String> redisTemplate;
    
	@Transactional(rollbackFor = Exception.class)
    private boolean reduceStock(String stockId,Integer reduceQuanity) {
        // 是否加锁成功
        Boolean locked = false;
        try {
        	// 加锁,设置锁超时时间,等待锁的时间
            locked = redisLock.tryLock(stockId, 120,20);
            if (!locked) {
                // 给原来的锁追加时间
                redisLock.reLock(stockId, 120);
                throw new RuntimeException("当前库存有其他订单在操作");
            }
				// 库存是否足够
				if(getStockQuantity(stockId)>reduceQuanity){
				     // 扣减库存
				int count = 	reduceQuantity(stockId,reduceQuanity);
					if(count==0){
					throw new RuntimeException("库存扣减失败");
					}
				}
            return true;
        } finally {
            // 业务处理成功后释放锁
            if (locked) {
                redisLock.unlock(stockId);
            }
        }
    }
	public Integer getStockQuantity(String stockId){
		// select quantity  from stock  where id = #{stockId}
	}
	public int reduceQuantity(String stockId,Integer quantity){
	            //  update stock set quantity = quantity - #{quantity}        where id = #{stockId} 
	}

提示:需要注意的是所有的业务逻辑都应该写在try{}块中,finally 记得释放锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值