一、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
# 端口,默认为6379
port: 6379
# 数据库索引
database: 5
# 密码
password:
# 连接超时时间
timeout: 60s
lettuce:
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;
@Bean
public 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 {
@Resource
private 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 {
@Resource
private RedissonLock redissonLock;
@GetMapping("lockTest")
public void lockTest(String key) {
try {
// 加锁
redissonLock.lock(key);
System.out.println("获取到锁,开始执行任务");
// 模拟业务操作
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁
redissonLock.unlock(key);
System.out.println("任务执行完毕,释放锁");
}
}
总结
Lock和tryLock的区别