SpringBoot Redis分布式锁

SpringBoot整合Redis分布式锁教程

章目录
提示:从今天起,撸起袖子跟着我加油干


提示:如有疑问请私信联系

前言

使用Spring Boot 可以非常方便、快速搭建项目,使我们不用关心框架之间的兼容性,适用版本等各种问题,我们想使用任何东西,仅仅添加一个配置就可以。


提示:以下是本篇文章正文内容,下面案例可供参考

一、技术介绍

1.Redis是什么?

Redis 是一个高性能的key-value数据库,redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。

2.分布式锁是什么?

分布式锁是为了防止分布式系统中的多个进程之间相互干扰的一种分布式协调技术。

二、使用步骤

1.引入maven库

代码如下(示例):

	 	<parent>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-parent</artifactId>
	        <version>2.4.1</version>
	        <relativePath/>
	    </parent>
       <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.4.1</version>
        </dependency>
    </dependencies>

2.封装Redis分布式锁工具类

代码如下(示例):

package com.hyh.redis.helper;

import com.hyh.utils.common.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁助手
 *
 * @Author: heyuhua
 * @Date: 2020/1/6 17:15
 */
@Component
public class RedisDistributionLockHelper {

    /**
     * 日志
     */
    private static final Logger LOG = LoggerFactory.getLogger(RedisDistributionLockHelper.class);
    /*** 分布式锁key ***/
    private static final String DISTRIBUTION_LOCK_KEY = "distribut_lock_";
    /*** 分布式锁过期时间 ***/
    private static final Integer EXPIRE_TIME = 30;
    /*** 每次自旋睡眠时间 ***/
    private static final Integer SLEEP_TIME = 50;
    /*** 分布式锁自旋次数 ***/
    private static final Integer CYCLES = 10;
    /**
     * redis模板调用类
     */
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        LOG.info("---redis分布式锁助手初始化----");
    }

    /**
     * 加锁
     *
     * @param key   加锁唯一标识
     * @param value 释放锁唯一标识(建议使用线程ID作为value)
     */
    public void lock(String key, String value) {
        lock(key, value, EXPIRE_TIME);
    }

    /**
     * 加锁
     *
     * @param key     加锁唯一标识
     * @param value   释放锁唯一标识(建议使用线程ID作为value)
     * @param timeout 超时时间(单位:S)
     */
    public void lock(String key, String value, Integer timeout) {
        Assert.isTrue(StringUtils.isNotBlank(key), "redis locks are identified as null.");
        Assert.isTrue(StringUtils.isNotBlank(value), "the redis release lock is identified as null.");
        int cycles = CYCLES;
        // ----- 尝试获取锁,当获取到锁,则直接返回,否则,循环尝试获取
        while (!tryLock(key, value, timeout)) {
            // ----- 最多循环10次,当尝试了10次都没有获取到锁,抛出异常
            if (0 == (cycles--)) {
                LOG.error("redis try lock fail. key: {}, value: {}", key, value);
                throw new RuntimeException("redis try lock fail.");
            }
            try {
                TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
            } catch (Exception e) {
                LOG.error("history try lock error.", e);
            }
        }
    }

    /**
     * 尝试获取锁
     *
     * @param key     加锁唯一标识
     * @param value   释放锁唯一标识(建议使用线程ID作为value)
     * @param timeout 超时时间(单位:S)
     * @return [true: 加锁成功; false: 加锁失败]
     */
    private boolean tryLock(String key, String value, Integer timeout) {
        Boolean result = redisTemplate.opsForValue().setIfAbsent(DISTRIBUTION_LOCK_KEY + key, value, timeout, TimeUnit.SECONDS);
        return result != null && result.booleanValue();
    }

    /**
     * 释放锁
     *
     * @param key   加锁唯一标识
     * @param value 释放锁唯一标识(建议使用线程ID作为value)
     */
    public void unLock(String key, String value) {
        Assert.isTrue(StringUtils.isNotBlank(key), "redis locks are identified as null.");
        Assert.isTrue(StringUtils.isNotBlank(value), "the redis release lock is identified as null.");
        key = DISTRIBUTION_LOCK_KEY + key;
        // ----- 通过value判断是否是该锁:是则释放;不是则不释放,避免误删
        if (value.equals(redisTemplate.opsForValue().get(key))) {
            redisTemplate.opsForValue().getOperations().delete(key);
        }
    }


    /**
     * 注销
     */
    @PreDestroy
    public void destory() {
        LOG.info("---redis分布式锁助手注销----");
    }
}



3.配置文件

代码如下(示例):

server:
  port: 8088
spring:
  #redis配置
  redis:
    host: 192.168.6.134
    port: 30511
    password:
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 500
        min-idle: 0
    lettuce:
      shutdown-timeout: 0

4.单元测试

代码如下(示例):

@Autowired
    private RedisDistributionLockHelper redisDistributionLockHelper;

    /**
     * 测试分布式Redis锁
     */
    @Test
    public void testLock() {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 100, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(200));
        int idx = 100;
        while (--idx > 0) {
            threadPoolExecutor.execute(() -> {
                try {
                    redisDistributionLockHelper.lock("hyh", Thread.currentThread().getId() + "");
                    //正确结果是只有一个线程获取锁成功,才符合我们锁定资源的效果
                    System.out.println("---获取锁成功,当前线程ID为【" + Thread.currentThread().getId() + "】---");
                } catch (RuntimeException runtimeException) {
                    System.out.println("---获取锁失败,当前线程ID为【" + Thread.currentThread().getId() + "】---");
                }
            });
            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (Exception e) {
                System.err.println("error:" + e.getMessage());
            }
        }
        //线程池使用局部变量使用时记得手动关闭
        threadPoolExecutor.shutdown();
    }

总结

是不是感觉很简单?关注我带你揭秘更多Redis高级用法
源码地址:点此查看源码.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

消灭知识盲区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值