李锋镝的博客

  • 首页
  • 时间轴
  • 留言
  • 插件
  • 左邻右舍
  • 关于我
    • 关于我
    • 另一个网站
  • 知识库
  • 赞助
Destiny
自是人生长恨水长东
  1. 首页
  2. 原创
  3. 技术
  4. 正文

RedisTemplate和Redisson的区别

2025年5月29日 15点热度 0人点赞 0条评论

1、Redisson和RedisTemplate的什么区别

一、功能方面:

Redisson:
提供了丰富的分布式数据结构和服务,例如分布式锁、分布式集合(包括分布式列表、集合、映射、队列、阻塞队列、双端队列、优先队列等)、分布式对象(如分布式对象、原子数、位图等)以及分布式服务(如分布式远程服务、分布式调度服务、分布式映射存储等)。它对Redis的操作进行了高度抽象和封装,极大地简化了分布式系统的开发。例如,使用Redisson的分布式锁可以这样:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonExample {
    public static void main(String[] args) {
        // 创建Redisson客户端配置
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        // 创建Redisson客户端
        RedissonClient redisson = Redisson.create(config);
        // 获取锁对象
        RLock lock = redisson.getLock("myLock");
        try {
            // 加锁
            lock.lock();
            // 在此执行需要加锁的代码逻辑
            System.out.println("执行加锁后的操作");
        } finally {
            // 解锁
            lock.unlock();
        }
        // 关闭Redisson客户端
        redisson.shutdown();
    }
}

上述代码首先创建了Redisson的配置对象,将Redis服务地址添加进去,接着创建Redisson客户端。通过getLock方法获取一个锁对象,使用lock方法加锁,执行完操作后用unlock方法解锁。这样就实现了分布式锁的操作,而且Redisson的锁支持可重入、公平锁等高级特性,能很好地处理分布式环境下的并发问题。
支持异步操作,可利用RFuture接口来实现异步调用,提高系统的并发性能。例如,获取锁时可以使用lockAsync方法,后续可对RFuture进行相应处理,充分利用异步操作的优势。
RedisTemplate:
主要是对Redis的基本数据结构(如字符串、哈希、列表、集合、有序集合)进行操作的模板类。它是Spring Data Redis中的一部分,更侧重于对Redis基本操作的封装,开发者需要根据不同的数据结构选择不同的操作接口,操作相对更加底层。例如,使用RedisTemplate操作哈希表:

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.HashOperations;

public class RedisTemplateExample {
    private RedisTemplate<String, Object> redisTemplate;

    public void setHashValue() {
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
        hashOps.put("myHash", "key", "value");
    }
}

这里先通过opsForHash方法获取HashOperations接口,然后使用put方法将一个键值对放入哈希表中。其操作比较基础,对于一些复杂的分布式场景,需要开发者自己去实现相应的逻辑。

二、性能方面:

Redisson:
因为提供了大量高级功能和封装,可能会带来一定的性能开销,尤其是在一些复杂的分布式操作场景下。不过,对于需要这些高级功能的分布式系统开发,它能节省大量开发时间和精力,且其性能对于大多数分布式场景是可以接受的。
对于异步操作,如果使用得当,可以提高系统的并发性能,避免同步等待,减少阻塞。
RedisTemplate:
相对而言,它的性能开销可能较小,更适合一些对性能敏感且只需要使用Redis基本操作的简单场景。

三、使用场景方面:

Redisson:
适用于开发分布式系统,如分布式锁在分布式事务、分布式任务调度、分布式缓存更新等场景中非常有用;分布式集合可用于分布式存储和处理大量数据;分布式服务可实现远程调用、分布式执行任务等。在需要大量使用Redis高级功能,如解决分布式环境中的并发问题、数据一致性问题、分布式服务调用等场景下表现出色。
RedisTemplate:
适合对Redis进行简单操作的场景,例如简单的缓存存储和读取、基本的数据结构操作等,更适合在Spring框架中使用,并且对于开发者想要对Redis操作有更多控制权,愿意自己实现一些高级功能逻辑的情况,使用RedisTemplate可以更好地进行自定义操作。

四、开发体验方面:

Redisson:
开发体验较好,代码简洁,很多分布式功能可以通过简单的API调用实现,大大减少了开发分布式功能的代码量,降低了开发分布式系统的难度,提高了开发效率。
RedisTemplate:
对于熟悉Spring框架和Spring Data Redis的开发者来说,使用RedisTemplate比较顺手,但在处理分布式复杂功能时,需要开发者深入Redis命令,自己实现相关逻辑,开发难度可能会相对较高。

五、社区和维护方面:

Redisson:
有自己独立的社区和维护团队,会持续更新和完善功能,对Redis新特性的支持也比较及时,并且在分布式领域有一定的技术积累,能为使用其的开发者提供技术支持和文档。
RedisTemplate:
依托于Spring社区,能随着Spring框架的更新而更新,但在Redis分布式功能的扩展上可能相对依赖Spring官方的支持和社区贡献,对于Redis自身高级功能的更新和支持可能不如Redisson及时。
综上所述,Redisson更适合开发复杂的分布式系统,提供了很多高级的分布式解决方案,而RedisTemplate更适合简单的Redis操作和希望对Redis操作有更多自定义的开发者。

2、Redisson实现分布式锁

一、实现思路:

对于Redis的不同部署模式(单点、集群分片、哨兵模式),Redisson都提供了相应的配置方式来支持分布式锁的实现,但在细节和性能上会有一些区别。
在单点模式下,配置相对简单,直接指向单个Redis服务器即可。
集群分片模式下,需要配置多个Redis节点信息,Redisson会自动处理数据分片和节点间的通信,确保分布式锁的可靠性和性能。
哨兵模式下,需要配置哨兵节点信息,Redisson会根据哨兵节点来监控Redis主从的状态,在主节点故障时自动切换到新的主节点,保证分布式锁的可用性。

二、不同部署模式下的实现细节:

单点模式:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonSingleNodeLock {
    public static void main(String[] args) {
        // 创建Redisson配置
        Config config = new Config();
        // 设置Redis单点地址
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        // 创建Redisson客户端
        RedissonClient redisson = Redisson.create(config);
        // 获取锁对象
        RLock lock = redisson.getLock("myLock");
        try {
            // 加锁
            lock.lock();
            // 执行加锁后的业务逻辑
            System.out.println("Lock acquired, doing something...");
        } finally {
            // 解锁
            lock.unlock();
        }
        // 关闭Redisson客户端
        redisson.shutdown();
    }
}

上述代码中,使用config.useSingleServer().setAddress("redis://127.0.0.1:6379")配置了一个Redis单点地址,创建了Redisson客户端并获取锁。这种模式下,Redisson直接与该单点Redis服务器通信,实现简单,但存在单点故障风险。
集群分片模式:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;

public class RedissonClusterLock {
    public static void main(String[] args) {
        // 创建Redisson配置
        Config config = new Config();
        ClusterServersConfig clusterConfig = config.useClusterServers();
        // 添加多个Redis集群节点
        clusterConfig.addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001", "redis://127.0.0.1:7002");
        // 创建Redisson客户端
        RedissonClient redisson = Redisson.create(config);
        // 获取锁对象
        RLock lock = redisson.getLock("myLock");
        try {
            // 加锁
            lock.lock();
            // 执行加锁后的业务逻辑
            System.out.println("Lock acquired in cluster mode, doing something...");
        } finally {
            // 解锁
            lock.unlock();
        }
        // 关闭Redisson客户端
        redisson.shutdown();
    }
}

在集群分片模式下,通过config.useClusterServers()开启集群配置,使用clusterConfig.addNodeAddress添加多个Redis集群节点。Redisson会根据Redis集群的特点自动处理数据的分片存储和节点间的通信,分布式锁会分布在不同的节点上,提高了系统的性能和容错性。
哨兵模式:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;

public class RedissonSentinelLock {
    public static void main(String[] args) {
        // 创建Redisson配置
        Config config = new Config();
        SentinelServersConfig sentinelConfig = config.useSentinelServers();
        // 设置哨兵节点地址
        sentinelConfig.addSentinelAddress("redis://127.0.0.1:26379", "redis://127.0.0.1:26380");
        // 设置主节点名称
        sentinelConfig.setMasterName("mymaster");
        // 创建Redisson客户端
        RedissonClient redisson = Redisson.create(config);
        // 获取锁对象
        RLock lock = redisson.getLock("myLock");
        try {
            // 加锁
            lock.lock();
            // 执行加锁后的业务逻辑
            System.out.println("Lock acquired in sentinel mode, doing something...");
        } finally {
            // 解锁
            lock.unlock();
        }
        // 关闭Redisson客户端
        redisson.shutdown();
    }
}

在哨兵模式下,使用config.useSentinelServers()开启哨兵配置,通过sentinelConfig.addSentinelAddress添加哨兵节点地址,sentinelConfig.setMasterName设置主节点名称。Redisson会根据哨兵的监控信息,在主节点故障时自动切换到新的主节点,保证分布式锁在Redis主从切换时的有效性和可靠性。

三、区别总结:

单点模式:
配置简单,仅需指定一个Redis节点地址。
性能和可靠性取决于单个Redis服务器,存在单点故障风险,一旦该节点故障,分布式锁将无法使用。
适合开发测试环境或对可靠性要求不高的小型系统。
集群分片模式:
配置多个Redis节点,可充分利用集群的性能和存储能力。
分布式锁会根据Redis集群的特性在不同节点间分布,提高了系统的性能和存储容量。
需要注意集群的拓扑结构和节点的状态维护,确保集群的正常运行。
适合高负载、大规模数据存储和操作的系统。
哨兵模式:
主要利用哨兵节点监控Redis主从状态,在主节点故障时自动切换,保证分布式锁的可用性。
配置涉及哨兵节点地址和主节点名称,确保哨兵正常工作。
可以提高系统的容错性,适合对系统可用性要求较高,希望在主节点故障时能自动切换到新主节点的场景。

四、使用注意事项:

无论哪种模式,使用分布式锁时,都要确保加锁和解锁的操作在正确的代码块中执行,避免死锁或锁无法释放的情况。
在集群分片和哨兵模式下,要确保节点的网络和硬件配置合理,避免因网络延迟或硬件故障导致分布式锁的性能下降或失效。
对于不同的业务场景,选择合适的Redis部署模式和相应的Redisson配置,以平衡性能、可靠性和开发成本。
分布式锁的超时时间设置需要谨慎,避免因超时导致业务逻辑异常,同时要考虑不同部署模式下可能的网络延迟和Redis操作延迟对锁超时的影响。
总之,Redisson在不同的Redis部署模式下都能实现分布式锁,但不同模式在配置、性能、可靠性等方面有各自的特点,需要根据具体的业务需求和系统架构来选择合适的模式。

3、redisson获取锁

// 获取锁对象 
RLock lock = redisson.getLock("myLock"); 
try { 
    // 加锁 
    lock.lock(); 
    // 在此执行需要加锁的代码逻辑 
    System.out.println("执行加锁后的操作"); 
} finally { 
    // 解锁 
    lock.unlock(); 
}

一、RLock lock = redisson.getLock("myLock");的解释 :

这行代码的主要目的是从Redisson客户端中获取一个分布式锁对象,该对象的名称是"myLock"。
redisson.getLock("myLock")方法调用后,Redisson会根据锁的名称在Redis中创建或查找对应的锁信息,但此时并未真正加锁。
它返回的是一个RLock类型的对象,RLock是Redisson对分布式锁的接口,实现了java.util.concurrent.locks.Lock接口,同时提供了一些额外的特性,如可重入性、公平锁、锁的超时等,这些特性是对Redis分布式锁功能的增强。

二、lock.lock();的解释:

这行代码是对之前获取到的RLock对象lock进行加锁操作。
当调用lock.lock();时,Redisson会与Redis服务器通信,尝试获取锁。
如果锁是可用的(没有其他客户端持有该锁),当前客户端将获得该锁,后续代码将可以继续执行。
如果锁已被其他客户端持有,lock.lock();会阻塞当前线程,直到锁被释放或超时(可设置超时时间)。
它会在Redis中设置相应的锁键值,同时使用一些机制(如基于Redis的数据结构和算法)来保证分布式环境下的锁的互斥性和一致性,确保同一时间只有一个客户端可以获得该锁。

三、区别总结:

RLock lock = redisson.getLock("myLock");是获取锁对象的操作,是为加锁做准备,它只是一个对象的创建和获取步骤,不涉及实际的锁竞争和锁的持有。
lock.lock();是真正的加锁操作,会触发锁的竞争机制,尝试在Redis上获取锁,可能会阻塞线程,直到获取到锁或者超时。

四、示例代码的整体流程解释:

// 获取锁对象
RLock lock = redisson.getLock("myLock");
try {
    // 加锁
    lock.lock();
    // 在此执行需要加锁的代码逻辑
    System.out.println("执行加锁后的操作");
} finally {
    // 解锁
    lock.unlock();
}

首先通过redisson.getLock("myLock");获取名为"myLock"的分布式锁对象lock。
然后使用lock.lock();对这个锁进行加锁操作,如果当前没有其他客户端持有该锁,当前客户端会成功加锁,之后执行System.out.println("执行加锁后的操作");等业务逻辑。
最后在finally块中调用lock.unlock();确保锁会被释放,无论业务逻辑是否正常执行,这是一个良好的编程习惯,防止因异常导致锁无法释放,影响其他客户端对锁的使用。
总之,getLock是为加锁做准备,lock是实际的加锁操作,两者结合使用可以实现Redisson分布式锁的获取和使用,保障分布式环境下的资源竞争和互斥访问。

4、 getLock、getSpinLock、getRedLock、getReadWriteLock区别

一、不同锁的特点及用法:

getLock:

  • 特点:最常用的可重入锁,支持公平锁和非公平锁(默认),可设置超时防止死锁。
  • 用法:
    RLock lock = redisson.getLock("myLock");  
    try {  
      lock.lock(10, TimeUnit.SECONDS); // 加锁并设置超时时间  
      // 业务逻辑  
    } finally {  
      lock.unlock();  
    }  
  • 场景:适用于大多数分布式锁场景,如库存扣减、接口幂等性控制。

getSpinLock:

  • 特点:自旋锁,获取失败时循环尝试而非阻塞,减少线程上下文切换开销,但长时间自旋会消耗CPU。
  • 用法:
    RLock spinLock = redisson.getSpinLock("spinLock");  
    spinLock.lock(); // 自旋等待获取锁  
    try {  
      // 短时间业务逻辑  
    } finally {  
      spinLock.unlock();  
    }  
  • 场景:锁竞争不激烈且持有时间短的场景,如缓存更新操作。

getRedLock:

  • 特点:基于多节点的分布式锁(RedLock算法),需多数节点加锁成功才视为成功,防止单点故障。
  • 用法:
    RLock lock1 = redisson1.getLock("redLock");  
    RLock lock2 = redisson2.getLock("redLock");  
    RedLock redLock = new RedLock(lock1, lock2); // 传入不同节点的锁  
    try {  
      redLock.lock(30, TimeUnit.SECONDS); // 加锁需多数节点成功  
      // 高可靠性业务逻辑  
    } finally {  
      redLock.unlock();  
    }  
  • 场景:金融交易、分布式协调等对可靠性要求极高的场景。

getReadWriteLock:

  • 特点:读写锁,允许多个读操作并发,写操作独占,适用于读多写少场景。
  • 用法:
    RReadWriteLock rwLock = redisson.getReadWriteLock("rwLock");  
    // 写锁(独占)  
    RLock writeLock = rwLock.writeLock();  
    writeLock.lock();  
    try {  
      // 写操作  
    } finally {  
      writeLock.unlock();  
    }  
    // 读锁(共享)  
    RLock readLock = rwLock.readLock();  
    readLock.lock();  
    try {  
      // 读操作  
    } finally {  
      readLock.unlock();  
    }  
  • 场景:缓存系统、报表查询等读多写少的业务场景。

二、适合的场景总结:

锁类型 适用场景 典型场景举例
getLock 通用分布式锁需求 订单创建、库存扣减
getSpinLock 短时间锁竞争,需避免线程阻塞 秒杀活动中的瞬时资源抢占
getRedLock 多节点高可靠需求,防止单点故障 金融转账、分布式事务协调
getReadWriteLock 读写分离场景,提升读并发 商品详情页缓存、实时统计查询

5、使用Redisson,redis数据库都不设置密码吗

一、设置 Redis 密码的必要性:

在生产环境中,必须为Redis设置密码。未设置密码的Redis暴露在公网或未授权网络中,可能导致数据泄露、恶意攻击(如写入脏数据、删除数据)等安全风险。

二、Redisson中设置密码的方法:

单点模式:

Config config = new Config();  
config.useSingleServer()  
      .setAddress("redis://127.0.0.1:6379")  
      .setPassword("your-redis-password"); // 设置密码  
RedissonClient redisson = Redisson.create(config);  

集群模式:

Config config = new Config();  
ClusterServersConfig clusterConfig = config.useClusterServers();  
clusterConfig.addNodeAddress("redis://node1:7000", "redis://node2:7001")  
             .setPassword("your-redis-password"); // 集群节点统一密码  

哨兵模式:

Config config = new Config();  
SentinelServersConfig sentinelConfig = config.useSentinelServers();  
sentinelConfig.addSentinelAddress("redis://sentinel1:26379")  
              .setMasterName("mymaster")  
              .setPassword("your-redis-password"); // 哨兵和主从节点密码  

三、注意事项:

  • 密码需通过setPassword()方法显式配置,不可硬编码在代码中,建议从配置文件或环境变量读取。
  • 不同部署模式下,密码配置作用于所有关联的Redis节点(如集群中的所有分片、哨兵监控的主从节点)。

6、Redisson使用公平锁 怎样获取锁

一、公平锁实现思路:

公平锁保证线程按请求顺序获取锁,通过getFairLock()方法获取,底层维护等待队列,避免线程饥饿。

二、代码示例:

Config config = new Config();  
config.useSingleServer().setAddress("redis://127.0.0.1:6379");  
RedissonClient redisson = Redisson.create(config);  
RLock fairLock = redisson.getFairLock("fairLock"); // 获取公平锁  
try {  
    fairLock.lock(); // 按顺序加锁  
    // 公平调度业务逻辑  
} finally {  
    fairLock.unlock();  
}  

三、与非公平锁的区别:

维度 公平锁 非公平锁(默认)
获取顺序 严格按照请求顺序分配锁 不保证顺序,可能出现“插队”
性能 维护队列导致额外开销,性能略低 无队列开销,性能更高
适用场景 任务调度、资源排队(如抢购排队) 高并发且对顺序无要求的场景

7、RLock.unlock使用

一、潜在风险:

若锁因超时而自动释放,当前线程已不再持有锁,调用unlock()会抛出IllegalMonitorStateException。

二、安全解锁方案:

使用isHeldByCurrentThread()判断当前线程是否持有锁:

public void safeUnlock(RLock lock) {  
    if (lock != null && lock.isHeldByCurrentThread()) { // 检查线程持有状态  
        lock.unlock();  
    }  
}  
// 使用示例  
try {  
    lock.lock(5, TimeUnit.SECONDS); // 加锁并设置超时  
    // 业务逻辑  
} finally {  
    safeUnlock(lock); // 避免过期锁释放异常  
}  

三、原理:

isHeldByCurrentThread()通过Redis中存储的线程标识,判断当前线程是否为锁持有者,确保仅在持有锁时执行解锁操作。

总结

Redisson通过丰富的锁类型和部署模式适配,提供了一站式分布式解决方案,但需注意:

  1. 根据场景选择锁类型:简单场景用getLock,高可靠场景用RedLock,读多写少用读写锁。
  2. 避免默认配置陷阱:禁止使用默认线程池和未加密连接,生产环境必须配置密码和超时时间。
  3. 解锁安全:始终通过isHeldByCurrentThread()校验锁持有状态,防止过期锁释放异常。

合理使用Redisson可大幅简化分布式开发,但深入理解其原理和配置细节,是避免性能问题和安全漏洞的关键。

除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/archives/article/tech/4435

相关文章

  • SpringBoot 实现接口防刷的 5 种实现方案
  • Redisson分布式锁的watch dog自动续期机制
  • 深入理解Redis
  • SpringBoot基于redis的分布式锁的实现(源码)
  • 部署consul配置中心
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: Redis Redisson RedisTemplate 分布式 分布式锁
最后更新:2025年5月28日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >

文章评论

1 2 3 4 5 6 7 8 9 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55 57 58 60 61 62 63 64 65 66 67 69 72 74 76 77 78 79 80 81 82 85 86 87 90 92 93 94 95 96 97 98 99
取消回复

去年今日此门中,人面桃花相映红。
人面不知何处去,桃花依旧笑春风。

最新 热点 随机
最新 热点 随机
ReentrantLock深度解析 RedisTemplate和Redisson的区别 SpringBoot常用注解 CompletableFuture使用详解 金融级JVM深度调优实战的经验和技巧 SpringBoot 实现接口防刷的 5 种实现方案
玩博客的人是不是越来越少了?2024年11月1号 农历十月初一准备入手个亚太的ECS,友友们有什么建议吗?别再背线程池的七大参数了,现在面试官都这么问@Valid 和 @Validated 的区别SpringBoot 实现接口防刷的 5 种实现方案
微服务架构梳理总结(二) LDC是什么? 内存屏障浅析 CC知识共享协议各协议内容解释 Java枚举梳理总结一 网站升级到http/2
标签聚合
JVM ElasticSearch 分布式 K8s Spring 面试 设计模式 MySQL 文学 JAVA 日常 SQL docker SpringBoot 架构 Redis IDEA 多线程 教程 数据库
友情链接
  • i架构
  • LyShark - 孤风洗剑
  • 临窗旋墨
  • 博友圈
  • 博客录
  • 博客星球
  • 哥斯拉
  • 志文工作室
  • 搬砖日记
  • 旋律的博客
  • 旧时繁华
  • 林羽凡
  • 知向前端
  • 集博栈
  • 韩小韩博客

COPYRIGHT © 2025 lifengdi.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Dylan

津ICP备2024022503号-3