Java集成Redisson实现分布式锁(实战)
一、Redisson是什么
Redisson 是一个基于 Redis 实现的 Java 驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列分布式和可扩展的 Java 数据结构,还对 Redis 进行了封装,让开发者可以更便捷地使用 Redis。
二、Redisson作用
- 简化 Redis 操作:Redisson 为 Java 开发者提供了一套直观且易于使用的 API,能把 Redis 当作普通的 Java对象或集合来操作,从而减少了与 Redis 交互时的复杂度。例如,你可以像操作 Java 的Map一样操作 Redis 中的哈希表。
- 分布式锁和同步机制:Redisson实现了多种分布式锁和同步工具,如可重入锁、公平锁、读写锁等,能确保在分布式环境下多个节点之间的数据一致性和并发控制。
- 丰富的数据结构:它提供了分布式的Map、List、Set、Queue等数据结构,这些结构在分布式系统中能被多个节点共享和操作。
- 异步和反应式编程支持:Redisson 支持异步和反应式编程模型,可提升应用程序的性能和响应能力。
三、使用场景
- 分布式锁:在分布式系统中,多个服务可能会同时访问和修改共享资源,使用 Redisson 的分布式锁可以保证同一时间只有一个服务能够操作该资源,避免数据冲突。例如,在电商系统中,多个订单服务可能同时处理库存扣减的操作,使用分布式锁可以确保库存数据的准确性。
- 分布式集合:当需要在多个服务之间共享数据时,可以使用 Redisson的分布式集合。比如,在一个分布式的消息系统中,多个消费者服务可以通过分布式队列来处理消息。
- 分布式缓存:利用 Redisson 的分布式Map可以实现分布式缓存,将经常访问的数据存储在 Redis 中,减少数据库的访问压力,提高系统的性能。例如,在一个高并发的 Web 应用中,可以将用户的基本信息缓存在 Redis 中,当用户访问时直接从缓存中获取数据。
- 分布式信号量:在分布式系统中,信号量可用于控制对有限资源的访问。例如,在一个分布式的文件上传系统中,可以使用信号量来限制同时上传的文件数量。
四、使用
1、引入依赖:
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>${redisson.version}</version> <!--版本号根据项目适配-->
</dependency>
3、配置文件
# 数据源配置
spring:# redis 配置redis:# 地址host: 127.0.0.1# 端口,默认为6379port: 6379# 数据库索引database: 5# 密码password: # 连接超时时间timeout: 60slettuce:pool:# 连接池中的最小空闲连接min-idle: 0# 连接池中的最大空闲连接max-idle: 8# 连接池的最大数据库连接数max-active: 8# #连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms
3、配置类:
@Component
@RefreshScope
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Value("${spring.redis.password}")private String password;@Value("${spring.redis.database}")private Integer database;@Beanpublic RedissonClient redissonClient() {// 创建配置 指定redis地址及节点信息Config config = new Config();//单例模式config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password) // redis设置了密码,就需设置.setDatabase(database);// 根据config创建出RedissonClient实例并返回return Redisson.create(config);}
}
4、工具
@Slf4j
@Component
public class RedissonLock {@Resourceprivate RedissonClient redissonClient;/*** lock(), 拿不到lock就不罢休,不然线程就一直block*/public RLock lock(String key) {if (StringUtils.isBlank(key)) {return null;}RLock lock = redissonClient.getLock(key);try {lock = redissonClient.getLock(key);} catch (Exception e) {log.error("Failed to acquire lock for key: " + key, e);}return lock;}/*** leaseTime为加锁时间,单位为秒* @param key key* @param leaseTime 为加锁时间,单位为秒*/public RLock lock(String key, long leaseTime) {if (StringUtils.isBlank(key) || leaseTime <= 0) {return null;}RLock lock = redissonClient.getLock(key);try {lock.lock(leaseTime, TimeUnit.SECONDS);} catch (Exception e) {log.error("Failed to acquire lock for key: " + key, e);}return lock;}/*** timeout为加锁时间,时间单位由unit确定*/public RLock lock(String key, TimeUnit unit, long timeout) {if (StringUtils.isBlank(key) || timeout <= 0 || unit == null) {return null;}RLock lock = redissonClient.getLock(key);try {lock.lock(timeout, unit);} catch (Exception e) {log.error("Failed to acquire lock for key: " + key, e);}return lock;}/*** @param lockKey 锁 key* @param unit 单位* @param waitTime 等待时间* @param leaseTime 锁有效时间* @return 加锁成功? true:成功 false: 失败*/public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {RLock lock = redissonClient.getLock(lockKey);try {return lock.tryLock(waitTime, leaseTime, unit);} catch (InterruptedException e) {Thread.currentThread().interrupt();log.error("加锁失败: " + e.getMessage());return false;} catch (Exception e) {log.error("加锁过程中发生异常: " + e.getMessage());return false;}}/*** unlock** @param lockKey key*/public void unlock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();}}/*** unlock** @param lock 锁*/public void unlock(RLock lock) {lock.unlock();}
}
5、例子
@RestController
@Slf4j
public class RedissonController {@Resourceprivate RedissonLock redissonLock;@GetMapping("lockTest")public void lockTest(String key) {// 获取锁RLock lock = redissonLock.getLock(key);try {// 加锁lock.lock();System.out.println("获取到锁,开始执行任务");// 模拟业务操作Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.unlock();System.out.println("任务执行完毕,释放锁");}
}
总结
Lock和tryLock的区别