Redis快速入门(三)

2023-10-25 11:23:23 浏览数 (1)

一. Redis的Java客户端

二. Jedis

Jedis的官网地址:https://github.com/redis/jedis,通过一个最简单的Demo实现快速入门:

2.1.实现流程

代码语言:javascript复制
<!--引入jedis-->
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>4.3.1</version>
</dependency>
<!--单元测试-->
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>5.7.0</version>
  <scope>test</scope>
</dependency>
代码语言:javascript复制
private Jedis jedis;
@BeforeEach
    void setUp(){
    //1.建立连接
    /*方式一直接创建*/
    //jedis = new Jedis("192.168.80.3", 6379);
    /*方式二使用连接池创建*/
    jedis = JedisConnectionFactory.getJedis();
    //2.设置密码
    jedis.auth("123456");
    //3.选库
    jedis.select(0);
}
代码语言:javascript复制
    @Test
    void testString(){
        //存入数据
        String result = jedis.set("name", "lmj");
        System.out.println("result=" result);
        //读取数据
        String name = jedis.get("name");
        System.out.println("name=" name);
    }
代码语言:javascript复制
    @AfterEach
    void tearDown(){
        if(jedis!=null){
            jedis.close();
        }
    }

查看运行结果


2.2. 小结——Jedis的使用基本步骤

  1. 引入依赖
  2. 创建Jedis对象,建立连接
  3. 使用Jedis,方法名与Redis命令一致
  4. 释放资源

2.3.Jedis连接池

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。

代码语言:javascript复制
public class JedisConnectionFactory {
    private static final JedisPool jedisPool;
    static {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(8);  //最大连接数
        poolConfig.setMaxIdle(8);   //最大空闲连接数
        poolConfig.setMinIdle(0);   //最小空闲连接
        poolConfig.setMaxWaitMillis(1000);  //空闲等待时间
        jedisPool = new JedisPool(poolConfig,"192.168.80.3",6379,1000,"123456");
    }
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

三.SpringDataRedis

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址

3.1. 优点

  1. 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  2. 提供了RedisTemplate统一API来操作Redis
  3. 支持Redis的发布订阅模型
  4. 支持Redis哨兵和Redis集群
  5. 支持基于Lettuce的响应式编程
  6. 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
  7. 支持基于Redis的JDKCollection实现

3.2. 常用API

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

3.3. 入门案例

SpringBoot已经提供了对SpringDataRedis的支持:

代码语言:javascript复制
<!--引入redis依赖-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--引入common-pool-->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>

代码语言:javascript复制
spring:
  redis:
    host: 192.168.80.3
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms

代码语言:javascript复制
@SpringBootTest
class JedisDemo2ApplicationTests {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("name","ljz");
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name=" name);
    }
}


3.4. 小结——SpringDataRedis的使用步骤:

1.引入spring-boot-starter-data-redis依赖 2.在application.yml配置Redis信息 3.注入RedisTemplate


3.5. SpringDataRedis的序列化方式

RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:

  • 缺点:
    • 可读性差
    • 内存占用较大
  • 默认的JDK序列化源码解析
    • 关于序列化现象的解读
  1. RedisTemplate类默认作为集合泛型
  2. 存入的value值为中文字符
  3. 在程序运行前后分别对redis进行两次get name得到的结果并没有发生改变
  4. 通过keys *找到了JDK序列化得到的"小李"真正的键值对
  • Debug调试
  1. 进入set方法:
    1. value被rawValue()进行装饰
    2. 将结果由Java转化成字节
  1. 进入装饰器rawValue(),返回value的序列化值
  1. 进入到JdkSerializationRedisSerializer
  1. 最终将Java对象通过ObjectOutputStrem转化成字节数据
  • 使用自定义RedisTemplate的序列化方式
    • 关于RedisSerializer的实现类(选中 H查看接口/类的实现类)
代码语言:javascript复制
  - JdkSerializationRedisSerializer(默认,不推荐使用)
  - StringRedisSerializer(专门用于处理字符串)
     -  字符串若想转字节存入Redis只需调用getBytes()即可
     - key或hashkey均为String时使用该实现
  - GenericJackson2JsonRedisSerializer(若value为对象时使用)
  • 小结
    • key用String
    • value用json

3.6. 自定义序列化

  • 引入Jackson依赖
代码语言:javascript复制
<!--引入Jackson依赖-->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
</dependency>
  • 编写配置类
代码语言:javascript复制
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        //创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //设置连接工厂
        template.setConnectionFactory(redisConnectionFactory);
        //创建JSON序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        //设置key的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        //设置value的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(RedisSerializer.json());
        //返回
        return template;
    }
}
  • 测试结果

3.7. 自定义序列化Java对象

  • 引入lombok依赖
代码语言:javascript复制
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>
  • 创建对象类Entity.User
代码语言:javascript复制
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private int age;
}
  • 编写测试代码
代码语言:javascript复制
	@Test
    void testSaveUser(){
        //写入数据
        redisTemplate.opsForValue().set("user:100",new User("小李",24));
        //获取数据
        User user = (User) redisTemplate.opsForValue().get("user:100");
        System.out.println("user=" user);
    }
  • 运行结果
  • 小结
    • 尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如运行结果:
    • 为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
  • StringRedisTemplate运行过程

为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。


Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去自定义RedisTemplate的过程:

  • 直接使用StringRedisTemplate
代码语言:javascript复制
private static final ObjectMapper mapper = new ObjectMapper();
	@Test
    void testSaveUser() throws JsonProcessingException {
        //创建对象
        User user = new User("小李", 24);
    	//手动序列化
    	String json = mapper.writeValueAsString(user);
    	//写入数据
    	stringRedisTemplate.opsForValue().set("user:200",json);
    	//获取数据
    	String json1 = stringRedisTemplate.opsForValue().get("user:200");
    	//手动反序列化
    	User user1 = mapper.readValue(json1, User.class);
    	System.out.println("user1=" user1);
	}
代码语言:javascript复制
  - 运行结果
  • 操作Hash对象
代码语言:javascript复制
@Test
    void testHash(){
        stringRedisTemplate.opsForHash().put("user:300","name","小李");
        stringRedisTemplate.opsForHash().put("user:300","age","24");

        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries("user:300");
        System.out.println("map=" map);
    }
代码语言:javascript复制
  - 运行结果

3.8. RedisTemplate的两种序列化实践方案:

方案一: 1.自定义RedisTemplate 2.修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer 方案二: 1.使用StringRedisTemplate 2.写入Redis时,手动把对象序列化为JSON 3.读取Redis时,手动把读取到的JSON反序列化为对象

0 人点赞