RedisTemplate和Redisson的使用和区别

文章目录

  • [一. 数据缓存](#一. 数据缓存)
    • [1.1 **为什么要用缓存**](#1.1 为什么要用缓存)
    • [1.2 缓存的实现](#1.2 缓存的实现)
    • [1.3 Redis](#1.3 Redis)
    • [1.4 Redis 数据结构](#1.4 Redis 数据结构)
    • [1.5 实现方式](#1.5 实现方式)
    • [1.6 对比](#1.6 对比)
    • [1.7 实现定时预热缓存](#1.7 实现定时预热缓存)
      • [1.7.1 什么是热缓存](#1.7.1 什么是热缓存)
      • [1.7.2 什么时候用缓存预热](#1.7.2 什么时候用缓存预热)
      • [1.7.3 缓存预热带来的问题](#1.7.3 缓存预热带来的问题)
      • [1.7.4 怎么实现缓存预热](#1.7.4 怎么实现缓存预热)
      • [1.7.5 预热缓存的注意点](#1.7.5 预热缓存的注意点)
      • [1.7.6 缓存预热 - 定时任务](#1.7.6 缓存预热 - 定时任务)
  • [二. RedisTemplate和Redisson](#二. RedisTemplate和Redisson)
    • [2.1 简介](#2.1 简介)
    • [2.2 主要区别](#2.2 主要区别)
    • [2.3 总结](#2.3 总结)
  • [三. 如何使用RedisTemplate](#三. 如何使用RedisTemplate)
    • [3.1 导入依赖](#3.1 导入依赖)
    • [3.2 配置application.yml](#3.2 配置application.yml)
    • [3.3 配置序列化](#3.3 配置序列化)
    • [3.4 测试](#3.4 测试)
  • [四. 如何使用Redisson](#四. 如何使用Redisson)
    • [4.1 导入依赖](#4.1 导入依赖)
    • [4.2 配置application.yml](#4.2 配置application.yml)
    • [4.3 配置Redisson](#4.3 配置Redisson)
    • [4.4 测试](#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. 在启动类上加注解
java 复制代码
@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 导入依赖

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.6.4</version>
</dependency>

3.2 配置application.yml

java 复制代码
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存储非字符串类型的数据时,你需要自定义序列化器来处理这些数据。

java 复制代码
/**
 *
 *  自定义序列化
 *
 */
@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,测试代码如下

java 复制代码
@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 导入依赖

java 复制代码
<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.19.1</version>
</dependency>  

4.2 配置application.yml

java 复制代码
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


    }
}
相关推荐
Fly不安全14 分钟前
Web安全:缓存欺骗攻击;基于缓存、CDN的新型Web漏洞
nginx·web安全·缓存·web·cdn·缓存欺骗攻击
明月看潮生18 分钟前
青少年编程与数学 02-007 PostgreSQL数据库应用 11课题、视图的操作
数据库·青少年编程·postgresql·编程与数学
阿猿收手吧!25 分钟前
【Redis】Redis入门以及什么是分布式系统{Redis引入+分布式系统介绍}
数据库·redis·缓存
奈葵29 分钟前
Spring Boot/MVC
java·数据库·spring boot
落霞的思绪29 分钟前
Redis实战(黑马点评)——涉及session、redis存储验证码,双拦截器处理请求
spring boot·redis·缓存
leegong2311137 分钟前
Oracle、PostgreSQL该学哪一个?
数据库·postgresql·oracle
中东大鹅42 分钟前
MongoDB基本操作
数据库·分布式·mongodb·hbase
夜光小兔纸1 小时前
Oracle 普通用户连接hang住处理方法
运维·数据库·oracle
Sunny_lxm1 小时前
<keep-alive> <component ></component> </keep-alive>缓存的组件实现组件,实现组件切换时每次都执行指定方法
前端·缓存·component·active
兩尛3 小时前
订单状态定时处理、来单提醒和客户催单(day10)
java·前端·数据库