前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java项目集成Redisson分布式锁

Java项目集成Redisson分布式锁

作者头像
程序员云帆哥
发布2022-05-12 11:09:00
3450
发布2022-05-12 11:09:00
举报
文章被收录于专栏:程序员云帆哥

文章目录

一、为什么需要分布式锁?

   因为Java中的锁,只作用于单个JVM实例上。而当下在互联网技术架构中,大家都用的分布式架构了,应用部署到多个服务器,这种情况下,线程之间的锁机制,就没作用了。为了解决这个问题,我们就引入分布式锁。

二、分布式锁要满足哪些要求呢?

(1)排他性:在同一时间只会有一个客户端能获取到锁,其它客户端无法同时获取。 (2)避免死锁:这把锁在一段有限的时间之后,一定会被释放。 (3)高可用:获取或释放锁的机制必须高可用且性能佳。

三、分布式锁的实现方式

这里只讲基于Redis实现的分布式锁,需要引入Redisson。

1、引入依赖

代码语言:javascript
复制
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>${redisson.version}</version>
</dependency>

2、配置类

代码语言:javascript
复制
@Configuration
public class RedissonConfig {
    @Value("${spring.redis.host}")
    private String address;

    @Value("${spring.redis.port}")
    private String port;

    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.database}")
    private Integer database;

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() {
        Config config = new Config();
        address = StringUtils.strip(address.trim(), ",");
        String[] addressList = address.split(",");
        if (addressList.length == 1) {
            config.useSingleServer().setDatabase(database).setAddress("redis://" + addressList[0] + ":" + port);
            if (StringUtils.isNotEmpty(password)) {
                config.useSingleServer().setPassword(password);
            }
        } else {
            ClusterServersConfig clusterServersConfig = config.useClusterServers().setScanInterval(2000);
            for (String address : addressList) {
                clusterServersConfig.addNodeAddress("redis://" + address + ":" + port);
                if (StringUtils.isNotEmpty(password)) {
                    clusterServersConfig.setPassword(password);
                }
            }
        }

        return Redisson.create(config);
    }
}

3、配置文件

代码语言:javascript
复制
spring:
	redis:
	    host: 127.0.0.1
	    port: 6379
	    password: 
	    database: 0        # Redis数据库索引(默认为0)
	    lettuce:
	      pool:
	        max-active: 8   # 连接池最大连接数(使用负值表示没有限制) (默认为8)
	        max-wait: 0    # 连接池最大阻塞等待时间(使用负值表示没有限制) (默认为-1)
	        max-idle: 8    # 连接池中的最大空闲连接 (默认为8)
	        min-idle: 0    # 连接池中的最小空闲连接 (默认为0)

4、RedisOpService(接口)

代码语言:javascript
复制
public interface RedisOpService {
    Boolean isLocked(String lockName);

    Boolean lock(String lockName);

    Boolean unlock(String lockName);
}

5、RedisOpServiceImpl(实现类)

代码语言:javascript
复制
@Service
@Slf4j
public class RedisOpServiceImpl implements RedisOpService {
    @Resource
    private RedissonClient redissonClient;

    @Override
    public Boolean isLocked(String lockName) {
        RLock rLock = redissonClient.getLock(lockName);
        return rLock.isLocked();
    }

    @Override
    public Boolean lock(String lockName) {
        try {
            RLock rLock = redissonClient.getLock(lockName);
            // 锁一段时间后自动释放,防止死锁
            rLock.lock(10, TimeUnit.SECONDS);
            log.info("RedisLock lock [{}] success", lockName);
        } catch (Exception e) {
            log.error("RedisLock lock [{}] Exception:", lockName, e);
            return false;
        }
        return true;
    }

    @Override
    public Boolean unlock(String lockName) {
        try {
            RLock rLock = redissonClient.getLock(lockName);
            rLock.unlock();
            log.info("RedisLock unlock [{}] success", lockName);
        } catch (Exception e) {
            log.error("RedisLock unlock [{}] Exception:", lockName, e);
            return false;
        }
        return true;
    }
}

6、RedisController

代码语言:javascript
复制
@RestController
@Slf4j
public class RedisController {
    @Resource
    private RedisOpService redisOpService;

    @GetMapping("test")
    public void test() {
        // 分布式锁处理,情况1:有竞争时,后面的请求报错丢弃,及时响应消息“请稍后重试”
        String lockName = "test:" + 666;
        if (redisOpService.isLocked(lockName)) {
            throw new RuntimeException("请稍后重试");
        }
        try {
            if (redisOpService.lock(lockName)) {
                log.info("执行业务逻辑");
            }
        } catch (Exception e) {
            log.error("异常", e);
        } finally {
            redisOpService.unlock(lockName);
        }
    }
	
	@GetMapping("test2")
    public void test2() {
        // 分布式锁处理,情况2:有竞争时,阻塞等待,依次获取锁->执行->释放锁,直到都处理完成
        String lockName = "test:" + 777;
        try {
            if (redisOpService.lock(lockName)) {
                log.info("执行业务逻辑");
            }
        } catch (Exception e) {
            log.error("异常", e);
        } finally {
            redisOpService.unlock(lockName);
        }
    }
}

两种应用场景:

  • 情况1:有竞争时,后面的请求报错丢弃,及时响应消息“请稍后重试”;
  • 情况2:有竞争时,阻塞等待,依次获取锁->执行->释放锁,直到都处理完成。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、为什么需要分布式锁?
  • 二、分布式锁要满足哪些要求呢?
  • 三、分布式锁的实现方式
    • 1、引入依赖
      • 2、配置类
        • 3、配置文件
          • 4、RedisOpService(接口)
            • 5、RedisOpServiceImpl(实现类)
              • 6、RedisController
              相关产品与服务
              云数据库 Redis
              腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档