当前位置: 首页 > article >正文

RedisTemplate和Redisson的使用和区别

文章目录

  • 一. 数据缓存
    • 1.1 **为什么要用缓存**
    • 1.2 缓存的实现
    • 1.3 Redis
    • 1.4 Redis 数据结构
    • 1.5 实现方式
    • 1.6 对比
    • 1.7 实现定时预热缓存
      • 1.7.1 什么是热缓存
      • 1.7.2 什么时候用缓存预热
      • 1.7.3 缓存预热带来的问题
      • 1.7.4 怎么实现缓存预热
      • 1.7.5 预热缓存的注意点
      • 1.7.6 缓存预热 - 定时任务
  • 二. RedisTemplate和Redisson
    • 2.1 简介
    • 2.2 主要区别
    • 2.3 总结
  • 三. 如何使用RedisTemplate
    • 3.1 导入依赖
    • 3.2 配置application.yml
    • 3.3 配置序列化
    • 3.4 测试
  • 四. 如何使用Redisson
    • 4.1 导入依赖
    • 4.2 配置application.yml
    • 4.3 配置Redisson
    • 4.4 测试

一. 数据缓存

1.1 为什么要用缓存

用户数量很大,导致数据查询慢,导致页面加载的时间过长。

用缓存:提前把数据取出来保存好(通常保存到读写更快的介质,比如内存),就可以更快地读写。

1.2 缓存的实现

●Redis(分布式缓存)
●memcached(分布式)
●Etcd(云原生架构的一个分布式存储,存储配置,扩容能力)
●ehcache(单机)
● 本地缓存(Java 内存 Map)
● Caffeine(Java 内存缓存,高性能)
● Google Guava

单机缓存存在的问题:

  1. 得到的数据不一致
  2. 获取不到资源

分布式缓存:

  1. 用户访问不同的服务器能获得到相同的资源数据
  2. 也就是在一个公共的服务器上存储数据,其他的服务器都讲数据读写在这个服务器上

redis 内存不能无限增加,一定要设置过期时间!!!

1.3 Redis

NoSQL 数据库
key - value 存储系统(区别于 MySQL,它存储的是键值对)

不是存那种表格之类的数据,不像数据库存储一行一行的数据,而是存储键值对的数据。

1.4 Redis 数据结构

String 字符串类型: name: “yupi”
List 列表:names: [“yupi”, “dogyupi”, “yupi”]
Set 集合:names: [“yupi”, “dogyupi”](值不能重复)
Hash 哈希:nameAge: { “yupi”: 1, “dogyupi”: 2 }
Zset 集合:names: { yupi - 9, dogyupi - 12 }(适合做排行榜)

bloomfilter(布隆过滤器,主要从大量的数据中快速过滤值,比如邮件黑名单拦截)
geo(计算地理位置)
hyperloglog(pv / uv)
pub / sub(发布订阅,类似消息队列)
BitMap (1001010101010101010101010101)二进制数据

1.5 实现方式

●Spring-Data-Redis**(推荐)**

Spring Data:通用的数据访问框架,定义了一组 增删改查 的接口

●Spring Data:通用的数据访问框架,定义了一组 增删改查 的接口mysql、redis、jpa
●Jedis: (独立于 Spring 操作 Redis 的 Java 客户端,要配合 Jedis Pool 使用)
●Lettuce
○高阶 的操作 Redis 的 Java 客户端
○异步、连接池
●Redisson:分布式操作 Redis 的 Java 客户端,让你像在使用本地的集合一样操作 Redis(分布式 Redis 数据网格)

1.6 对比

  1. 如果你用的是 Spring,并且没有过多的定制化要求,可以用 Spring Data Redis,最方便
  2. 如果你用的不是 SPring,并且追求简单,并且没有过高的性能要求,可以用 Jedis + Jedis Pool
  3. 如果你的项目不是 Spring,并且追求高性能、高定制化,可以用 Lettuce,支持异步、连接池
  4. 如果你的项目是分布式的,需要用到一些分布式的特性(比如分布式锁、分布式集合),推荐用 redisson

1.7 实现定时预热缓存

1.7.1 什么是热缓存

●数据量大时,可以提前将数据提前写入缓存,提高第一次访问的数据

●解决第一次访问时间过长,太长时间加载不出来页面,但是后面的访问页面就不会存在访问页面时间过长

●提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

1.7.2 什么时候用缓存预热

  1. 第一次访问时间比较长,但是后面的访问时间就很快一点。

  2. 第一次进入系统的加载时间过长

1.7.3 缓存预热带来的问题

  1. 增加开发成本(你要额外的开发、设计)
  2. 预热的时机和时间如果错了,有可能你缓存的数据不对或者太老
  3. 需要占用额外空间

1.7.4 怎么实现缓存预热

  1. 直接写个缓存刷新页面,上线时手工操作下。
  2. 数据量不大,可以在项目启动的时候自动进行加载。
  3. 定时任务,定时刷新缓存

1.7.5 预热缓存的注意点

  1. 缓存预热的意义(新增少、总用户多)

  2. 缓存的空间不能太大,要预留给其他缓存空间

  3. 缓存数据的周期(此处每天一次)

1.7.6 缓存预热 - 定时任务

  1. 在启动类上加注解
@EnableScheduling
public class UserCenterApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserCenterApplication.class, args);
    }
}
  1. 在方法上添加注解
// cron 秒 分 时 日 月 年(每天这一刻执行)
@Scheduled(cron = "0 26 22 * * *")
public void doPreCacheRecommendUser() {}

二. RedisTemplate和Redisson

2.1 简介

RedisTemplate和Redisson都是操作Redis的Java客户端库。

2.2 主要区别

RedisTemplate:

RedisTemplate则提供了一套更简洁和易用的API,方便开发人员进行数据读写操作,但相对于Redisson,其功能相对较少,如不支持分布式锁等。
RedisTemplate采用了Spring的整体架构,与Spring的各种组件相结合,因此在性能和可靠性上可能会有一些差异。
RedisTemplate作为Spring框架的一部分,与Spring集成度较高,使用起来更加方便。
RedisTemplate适用于基本的Redis操作场景,如缓存、消息队列等。
RedisTemplate采用了传统的同步编程模型,适合于传统的Java应用。
RedisTemplate将Redis的操作封装为一组方法,并提供了丰富的数据类型支持。

Redisson:

Redisson提供了更丰富和更高级的功能和API,比如分布式锁、分布式集合、分布式对象等。它的API设计更加灵活和面向对象,能够更方便地进行并发控制和数据共享。
Redisson基于Netty框架,它在连接池、线程池等方面进行了优化,以提高性能和可靠性。
Redisson则需要额外配置和引入依赖,使用起来相对繁琐一些。
Redisson更适用于需要高级Redis功能的场景,如分布式锁、分布式计数器等。
Redisson采用了Reactive编程模型,支持异步、响应式的操作方式,适合于高并发、高性能的应用。
Redisson将Redis的操作封装为一组对象,并提供了对应的操作方法,更加直观易用。

2.3 总结

RedisTemplate更适合于简单的Redis操作,比如简单缓存、简单消息队列;而Redisson则提供了更高级的功能,比如分布式系统、集群和哨兵模式、RxJava集成。

三. 如何使用RedisTemplate

3.1 导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.6.4</version>
</dependency>

3.2 配置application.yml

spring:
  # redis 配置
  redis:
    port: 6379
    host: localhost
    database: 0

3.3 配置序列化

使用 Redis 缓存高频访问用户信息时提到了自定义序列化器,为什么需要自定义序列化器,以及自定义序列化器的实现方式?

由于 Spring Boot Data Redis 默认使用 JDK 序列化器,会将存储到 Redis 的键值对转化为字节数组,不利于在 Redis 可视化工具中阅读、并且不利于跨语言兼容,所以需要指定序列化器。

所以我通过新建 RedisTemplateConfig 配置类来创建自定义的 RedisTemplate Bean,并且通过 redisTemplate.setKeySerializer(RedisSerializer.string()) 指定了 Redis Key 的序列化方式。

java自带的redistemplate只能查询字符串类型

是的,Java自带的RedisTemplate默认只支持序列化字符串类型。这是因为RedisTemplate是基于Spring框架的,而Spring Data Redis为了简化操作,默认使用了StringRedisSerializer来序列化和反序列化数据。这意味着当你使用RedisTemplate存储非字符串类型的数据时,你需要自定义序列化器来处理这些数据。

/**
 *
 *  自定义序列化
 *
 */
@Configuration
public class RedisTemplateConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        //创建RedisTemplate对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
       //设置连接工厂
        redisTemplate.setConnectionFactory(connectionFactory);
        //设置Key的序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());

        //创建Json序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        //设置Value的序列化
        redisTemplate.setValueSerializer(jsonRedisSerializer);

        return redisTemplate;
    }
}

3.4 测试

在测试包里创建测试类RedisTest,测试代码如下

@SpringBootTest
public class RedisTest {
    //
    @Resource
    private RedisTemplate redisTemplate;
    @Test
    void test(){
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //增
        valueOperations.set("yupiString","dog");
        valueOperations.set("yupiInt",1);
        valueOperations.set("yupiDouble",2.0);
        User user = new User();
        user.setId(1L);
        user.setUsername("yupi");
        valueOperations.set("yupiUser",user);
        //查
        Object yupi = valueOperations.get("yupiString");
        Assertions.assertTrue("dog".equals((String)yupi));
        yupi = valueOperations.get("yupiInt");
        Assertions.assertTrue(1==((Integer)yupi));
        yupi = valueOperations.get("yupiDouble");
        Assertions.assertTrue(2.0==((Double)yupi));
        System.out.println(valueOperations.get("yupiUser"));
//        valueOperations.set("yupiString","dog");
//        redisTemplate.delete("yupiString");
    }
}

四. 如何使用Redisson

4.1 导入依赖

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.19.1</version>
</dependency>  

4.2 配置application.yml

spring:
  # redis 配置
  redis:
    port: 6379
    host: localhost
    database: 0
    password: 123456

4.3 配置Redisson

@Configuration
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedissonConfig {

    private Integer database;

    private String host;

    private String password;

    private String port;
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useReplicatedServers()
                .setDatabase(database)
                .setPassword("".equals(password) ? null : password) // 这样没有密码就用默认值 null 有密码就用密码更加灵活
                .addNodeAddress(String.format("redis://%s:%s", host, port));
        return Redisson.create(config);
    }
}

4.4 测试

编写测试类来使用Redisson 实现分布式锁


@SpringBootTest
public class RedissonTest {

    @Resource
    private RedissonClient redissonClient;

    @Test
    void test() {
        // list,数据存在本地 JVM 内存中
        List<String> list = new ArrayList<>();
        list.add("yupi");
        System.out.println("list:" + list.get(0));

        list.remove(0);

        // 数据存在 redis 的内存中
        RList<String> rList = redissonClient.getList("test-list");
        rList.add("yupi");
        System.out.println("rlist:" + rList.get(0));
        rList.remove(0);

        // map
        Map<String, Integer> map = new HashMap<>();
        map.put("yupi", 10);
        map.get("yupi");

        RMap<Object, Object> map1 = redissonClient.getMap("test-map");

        // set

        // stack


    }
}

http://www.kler.cn/a/524823.html

相关文章:

  • PySide(PyQT)进行SQLite数据库编辑和前端展示的基本操作
  • Julia 之 @btime 精准测量详解
  • Deepseek技术浅析(一)
  • 论文阅读(十三):复杂表型关联的贝叶斯、基于系统的多层次分析:从解释到决策
  • redis缓存和springboot缓存包冲突怎么办
  • 【C++】设计模式详解:单例模式
  • 性能测试丨分布式性能监控系统 SkyWalking
  • 求职|基于Springboot的校园求职招聘系统设计与实现(源码+数据库+文档)
  • 【linux】linux缺少tar命令/-bash: tar:未找到命令
  • 单片机基础模块学习——NE555芯片
  • 安装zsh并美化
  • 10.5 流
  • Java坦克大战
  • 蛇年的第一篇博客:设想中的汉字编码
  • Sprintboot原理
  • VMware安装win10记录
  • MySQL备忘录
  • 上位机知识篇---Linux的shell脚本搜索、查找、管道
  • 【数据结构】初识链表
  • MongoDB常见的运维工具总结介绍
  • 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-19- 操作鼠标悬停(详细教程)
  • 代码随想录|动态规划 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组
  • Go学习:格式化输入输出
  • solon-flow 你好世界!
  • C++传送锚点的内存寻址:内存管理
  • G. Rudolf and CodeVid-23