SpringBoot 的 RedisTemplate、Redisson

这篇具有很好参考价值的文章主要介绍了SpringBoot 的 RedisTemplate、Redisson。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Jedis、Lettuce、Redisson的简介

优先使用Lettuce,
需要分布式锁,分布式集合等分布式的高级特性,添加Redisson结合使用。
对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。

1.1、Jedis

老牌Redis的Java客户端,提供比较全面的Redis命令的支持,
使用阻塞的I/O,方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。
Jedis客户端实例不是线程安全的,使直接连接redis server,需要通过连接池来使用Jedis,为每个jedis实例增加物理连接。

1.2、Lettuce

   SpringBoot2之后,默认就采用了lettuce。 
高级Redis客户端,基于Netty框架的事件驱动的通信层,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
Lettuce的API是线程安全的,可以操作单个Lettuce连接来完成各种操作,连接实例(StatefulRedisConnection)可在多个线程间并发访问。

1.3、Redisson

基于Netty框架的事件驱动的通信层,方法是异步的,API线程安全,可操作单个Redisson连接来完成各种操作。
实现了分布式和可扩展的Java数据结构,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。
提供很多分布式相关操作服务,如,分布式锁,分布式集合,可通过 Redis支持延迟队列。

二、SpringBoot 的 RedisTemplate

2.1、配置

<!--redis(spring-boot-starter-data-redis中包含的Lettuce)-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Lettuce使用线程池必要包-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!-- Redisson依赖 -->
<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.23.2</version>
</dependency>  
####################redis连接配置############
redis:
#   cluster:
#	nodes:
#	  - 127.0.0.1:7001
#	  - 127.0.0.1:7002
#	  - 127.0.0.1:7003
#	   host: 127.0.0.1
  port: 6379
  password: 123456
  database: 0
  timeout: 2000ms
  lettuce:
    pool:
      # 连接池最大连接数
      max-active: 20
      # 连接池中的最小空闲连接
      max-idle: 10
      # 连接池最大阻塞等待时间(使用负数表示没有限制,单位ms)
      max-wait: 3000

2.2、代码使用

2..2.1.配置 RedisTemplate

@Configuration
public class RedisConfig {
	/**
     * 创建 RedisTemplate,注入IOC容器
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置数据源的连接工厂(默认会传入框架中自带的(也就是读取完配置文件装配的)LettuceConnectionFactory)
        // 也可以自己定义,注入容器,再通过@Qualifier("")传进来 
        template.setConnectionFactory(factory);
        //设置key的序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
        return template;
    }
}

2..2.3.RedisTemplate 封装

@Component
public class RedisClient {
 
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
 
    /**
     * 指定缓存失效时间
     * @param key 键
     * @param time 时间(秒)
     */
    public boolean expire(String key,long time){
        try {
            if(time>0){
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long ttl(String key){
        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }
 
    //============================String=============================
    /**
     * 普通缓存获取
     * @param key 键
     * @return 值
     */
    public Object get(String key){
        return key==null?null:redisTemplate.opsForValue().get(key);
    }
 
    /**
     * 普通缓存放入
     * @param key 键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key,Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    public Boolean del(String key){
       return redisTemplate.delete(key);
    }
 
    //================================hash=================================
    /**
     * HashGet
     * @param key 键 不能为null
     * @param item 项 不能为null
     */
    public Object hget(String key,String item){
        return redisTemplate.opsForHash().get(key, item);
    }
 
    /**
     * 向 hash 表中放入数据,如果不存在将创建
     * @param key 键
     * @param item 项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key,String item,Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 删除hash表中的值
     * @param key 键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item){
        redisTemplate.opsForHash().delete(key,item);
    }
 
    //============================set=============================
    /**
     * 根据key获取Set中的所有值
     * @param key 键
     */
    public Set<Object> smembers(String key){
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 将数据放入set缓存
     * @param key 键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sadd(String key, Object...values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
 
 
    /**
     * 移除值为value的
     * @param key 键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long srem(String key, Object ...values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //===============================list=================================
 
    /**
     * 获取list缓存的内容
     * @param key 键
     * @param start 开始
     * @param end 结束  0 到 -1代表所有值
     */
    public List<Object> lrange(String key, long start, long end){
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     */
    public boolean rpush(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     */
    public boolean lpush(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 移除N个值为value
     * @param key 键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lrem(String key,long count,Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

三、SpringBoot 的 Redisson 

SpringBoot 的 RedisTemplate、Redisson,redis,数据库,缓存

Redisson官方文档: https://github.com/redisson/redisson/wiki

3.1、在之前的 Configuration 里添加 Bean

@Configuration
public class RedisConfig {
	
	// 锁前缀	
    private static final String SCHEMA_PREFIX = "redis://";
	
	// 超时时间
	private final long lockWatchTimeOut = 3000;	
	
	/**
     * 创建 RedisTemplate,注入IOC容器
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置数据源的连接工厂(默认会传入框架中自带的(也就是读取完配置文件装配的)LettuceConnectionFactory)
        // 也可以自己定义,注入容器,再通过@Qualifier("")传进来 
        template.setConnectionFactory(factory);
        //设置key的序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
        return template;
    }

   /**
     * 创建 RedissonClient,注入IOC容器
     */
    @Bean
    public RedissonClient redissonClient(RedisProperties redisProperties) {
        Config config = new Config();
        RedisProperties.Sentinel sentinel = redisProperties.getSentinel();
        RedisProperties.Cluster redisPropertiesCluster = redisProperties.getCluster();
        if (redisPropertiesCluster != null) {
            //集群redis
            ClusterServersConfig clusterServersConfig = config.useClusterServers();
            for (String cluster : redisPropertiesCluster.getNodes()) {
                clusterServersConfig.addNodeAddress(SCHEMA_PREFIX + cluster);
            }
            if (StringUtils.hasText(redisProperties.getPassword())) {
                clusterServersConfig.setPassword(redisProperties.getPassword());
            }
            clusterServersConfig.setTimeout((int) redisProperties.getTimeout().toMillis());
            clusterServersConfig.setPingConnectionInterval(30000);
        } else if (StringUtils.hasText(redisProperties.getHost())) {
            //单点redis
            SingleServerConfig singleServerConfig = config.useSingleServer().
                    setAddress(SCHEMA_PREFIX + redisProperties.getHost() + ":" + redisProperties.getPort());
            if (StringUtils.hasText(redisProperties.getPassword())) {
                singleServerConfig.setPassword(redisProperties.getPassword());
            }
            singleServerConfig.setTimeout((int) redisProperties.getTimeout().toMillis());
            singleServerConfig.setPingConnectionInterval(30000);
            singleServerConfig.setDatabase(redisProperties.getDatabase());
        } else if (sentinel != null) {
            //哨兵模式
            SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
            sentinelServersConfig.setMasterName(sentinel.getMaster());
            for (String node : sentinel.getNodes()) {
                sentinelServersConfig.addSentinelAddress(SCHEMA_PREFIX + node);
            }
            if (StringUtils.hasText(redisProperties.getPassword())) {
                sentinelServersConfig.setPassword(redisProperties.getPassword());
            }
            sentinelServersConfig.setTimeout((int) redisProperties.getTimeout().toMillis());
            sentinelServersConfig.setPingConnectionInterval(30000);
            sentinelServersConfig.setDatabase(redisProperties.getDatabase());
        }
        config.setLockWatchdogTimeout(lockWatchTimeOut);
        return Redisson.create(config);
    }

}

3.2、分布式锁

Redisson续期机制—看门狗机制:
1.启动定时任务重新给锁设置过期时间,默认过期时间是 30 秒,每 10 秒(默认事件的1/3)续期一次(补到 30 秒)
2.如果线程挂掉(服务器宕机),则不会续期。
3.只有lock.lock(); 会有看门狗机制;
4.lock.lock(10,,TimeUnit.SECONDS);手动设置过期时间的话,则不会有看门狗机制。文章来源地址https://www.toymoban.com/news/detail-657286.html

/**
 * 分布式Redis锁
 */
@Slf4j
public class DistributedRedisLock {

    @Autowired
    private RedissonClient redissonClient;

    // 加锁
    public Boolean lock(String lockName) {
        if (redissonClient == null) {
            log.info("DistributedRedisLock redissonClient is null");
            return false;
        }
        try {
            RLock lock = redissonClient.getLock(lockName);
            // 锁15秒后自动释放,防止死锁
            lock.lock(15, TimeUnit.SECONDS);
            // 加锁成功
            return true;
        } catch (Exception e) {
			e.printStackTrace();
            return false;
        }
    }

    // 释放锁
    public Boolean unlock(String lockName) {
        if (redissonClient == null) {
            log.info("DistributedRedisLock redissonClient is null");
            return false;
        }
        try {
            RLock lock = redissonClient.getLock(lockName);
            lock.unlock();
            // 释放锁成功
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

3.3、读写锁 

@Autowired
RedissonClient redisson;

@Autowired
RedisTemplate redisTemplate;

@ResponseBody
@GetMapping("/write")
public String writeValue(){
	RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
	RLock rLock = lock.writeLock();
	String s = "";
	try {
		s = UUID.randomUUID().toString();
		// 模拟业务时间    
		Thread.sleep(30000);
	} catch (Exception e){
		e.printStackTrace();
	}finally {
		rLock.unlock();
	}
	redisTemplate.opsForValue().set("writeValue",s);
	return s;
}

@GetMapping(value = "/read")
@ResponseBody
public String readValue() {
	String s = "";
	RReadWriteLock readWriteLock = redisson.getReadWriteLock("rw-lock");
	//加读锁
	RLock rLock = readWriteLock.readLock();
	try {
		rLock.lock();
		s = (String) redisTemplate.opsForValue().get("writeValue");
		TimeUnit.SECONDS.sleep(10);
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		rLock.unlock();
	}
	return s;
}

3.4、闭锁 

@GetMapping(value = "/lockDoor")
@ResponseBody
public String lockDoor() throws InterruptedException {
	RCountDownLatch lockDoor = redisson.getCountDownLatch("lockDoor");
	lockDoor.trySetCount(5); // 设置计数为5
	lockDoor.await(); //等待闭锁完成
	return "放假啦...";
}

@GetMapping(value = "/go/{id}")
public String go(@PathVariable("id") Integer id)  {
	RCountDownLatch lockDoor = redisson.getCountDownLatch("lockDoor");
	lockDoor.countDown(); // 计数减1
	return id+"班都走光了";
}

3.5、信号量 

@GetMapping(value = "/park")
@ResponseBody
public String park() {
	RSemaphore park = redisson.getSemaphore("park");
	try {
		park.acquire();// 获取一个信号量(redis中信号量值-1),如果redis中信号量为0了,则在这里阻塞住,直到信号量大于0,可以拿到信号量,才会继续执行。
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	return "ok";
}

@GetMapping(value = "/go")
@ResponseBody
public String go() {
	RSemaphore park = redisson.getSemaphore("park");
	park.release();  //释放一个信号量(redis中信号量值+1)
	return "ok";
}

到了这里,关于SpringBoot 的 RedisTemplate、Redisson的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java Web】利用Spring整合Redis,配置RedisTemplate

    1. 在config中加入RedisConfig配置类 2. 写个测试类测试一下 3. 注意事项 Redis不满足事务的原子性,原子性是指事务要么被全部执行,要么都不执行。但是Redis不支持回滚,就可能会出现有些语句执行成功,有些执行失败,因此具备原子性; Redis事务的三个阶段: 开始事务 命令入

    2024年02月09日
    浏览(14)
  • Redis哨兵集群搭建及RedisTemplate的哨兵模式配置详解

    本文详细介绍了Redis哨兵集群的原理、架构和工作流程,包括哨兵的功能作用、故障恢复机制、选举新的master等内容。同时,提供了哨兵集群架构示意图和实例准备、配置、启动、测试的步骤。此外,还介绍了如何在Spring的RedisTemplate中配置哨兵模式,实现Redis主从集群的自动切换和节点感知。

    2024年02月14日
    浏览(16)
  • Spring Boot 整合 Redis,使用 RedisTemplate 客户端

    1.1.1 添加依赖 redis 的依赖: 1.1.2 yml 配置文件 1.1.3 Config 配置文件 1.1.4 使用示例 注入 RedisTemplate,即可操作 Redis,简单示例如下: 1.2.1 RedisTemplate 简介 RedisTemplate 是 Spring Data Redis 项目的一部分,旨在简化在Java应用程序中使用 Redis 的过程。它提供了一组简单的方法,可以在

    2024年02月09日
    浏览(41)
  • 在Spring Boot微服务使用RedisTemplate操作Redis集群

    记录 :442 场景 :在Spring Boot微服务使用RedisTemplate操作Redis集群的缓存和队列等数据类型。 版本 :JDK 1.8,Spring Boot 2.6.3,redis-6.2.5。 1.微服务中 配置Redis信息 1.1在pom.xml添加依赖 pom.xml文件: 解析:spring-boot-starter-data-redis和spring-boot版本保持一致。 1.2在application.yml中配置Redis集群

    2024年02月12日
    浏览(12)
  • Redis 读写分离 使用redisTemplate执行lua脚本时,报错处理

    项目配置 redis架构 1主2从3哨兵模式 采用了读写分离模式 springboot使用 luttuce 项目使用redisTemplate执行lua脚本 测试代码 大致意思是说 在从节点上执行 写操作(实际上写操作是在lua脚本里面的) 为什么执行lua脚本会只走从节点? 在主从模式下,框架自身应该是可以区分读和写

    2024年02月17日
    浏览(18)
  • Redis之Redisson原理详解

    Redisson 顾名思义, Redis 的儿子,本质上还是 Redis 加锁,不过是对 Redis 做了很多封装,它不仅提供了一系列的分布式的 Java 常用对象,还提供了许多分布式服务。 Redisson 和 Jedis 、 Lettuce 有什么区别? Redisson 和它俩的区别就像一个用鼠标操作图形化界面,一个用命令行操作文

    2024年02月09日
    浏览(9)
  • Springboot+Redis:实现缓存 减少对数据库的压力

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 Redis实战与进阶 本专栏讲解Redis从原理到实践 这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn.net/   目录 缓存如何实现?

    2024年03月24日
    浏览(20)
  • redisTemplate.opsForValue().get(KEY)从Redis中取出的值为null 的解决方法

    redisTemplate.opsForValue().get(KEY)从Redis中取出的值为null 的解决方法 最近,博主在整理毕设时就遇到一个问题:我往Redis中存手机验证码,我把手机号当做key ,验证码当做value 存储到 Redis 中,但是在我在需要在登录操作中取验证码时遇到一个问题: 困惑: 我Redis 中明明存的有,

    2024年02月11日
    浏览(14)
  • 【征服redis5】redis的Redisson客户端

    目录 1 Redisson介绍 2. 与其他Java Redis客户端的比较 3.基本的配置与连接池 3.1 依赖和SDK 3.2 配置内容解析 4 实战案例:优雅的让Hash的某个Field过期 5 Redisson的强大功能 Redisson 最初由 GitHub 用户 “mrniko” 创建,并在 Apache 2.0 许可证下发布。它的目标是提供一组强大的工具和 API,

    2024年01月17日
    浏览(18)
  • Redis 整合中 Redisson 的使用

    大家好 , 我是苏麟 , 今天带来 Redisson 使用 . 官方文档 :  GitHub - redisson/redisson: Redisson - Easy Redis Java client with features of In-Memory Data Grid. Sync/Async/RxJava/Reactive API. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter,

    2024年02月11日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包