Redis

SpringBoot 操作数据:spring-data、jap、jdbc、mongodb、redis!

SpringBoot 在 2.x 之后,将原来使用的 Jedis 替换为了 lettuce

Jedis:采用的是直连,多个线程操作的话,是不安全的。如果想要避免不安全的,使用 jedis pool 连接池。更像 BIO 模式。

Lettuce:采用netty,实际可以在多个线程中共享,不存在线程不安全问题,可以减少线程数据。更像 NIO 模式

一、源码分析:RedisAutoConfiguration - Redis自动配置类

@Bean
@ConditionalOnMissingBean(name = "redisTemplate") // 可以自定义一个redisTemplate来替换这个默认的
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
   // 默认的 RedisTemplate 没有过多的设置,redis 对象都需要实例化!
   // 两个泛型都是 <Object,Object> 类型,在使用的时候需要强制转换 <String,Object>
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

@Bean
@ConditionalOnMissingBean // 由于 String 是 redis 中最常用的类型,所以说单独提出来一个bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

二、整合测试

1、导入依赖

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

2、配置连接

spring.redis.host=111.230.195.169
spring.redis.port=6379

3、测试

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

        // redisTemplate        操作不同的数据类型,api和Linux指令是一样的
        // opsForValue          操作字符串,类似String
        // opsForList           操作List,类似List
        // opsForHash           操作Hash,类似Hash
        // opsForSet            操作Set,类似Set
        // opsForZSet           操作ZSet,类似ZSet
        // opsForGeo            操作Geo,类似Geo
        // opsForHyperLogLog    操作HyperLogLog,类似HyperLogLog

        // 除了基本的操作,常用的方法都可以通过redisTemplate直接操作,比如:事务,和基本的CURD

        // 获取Redis连接对象
        // RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        // connection.flushDb();
        // connection.flushAll();
        redisTemplate.opsForValue().set("mykey", "DemoApplicationTests测试");
        System.out.println(redisTemplate.opsForValue().get("mykey"));
    }
}

查看数据库 - 写入Redis数据库成功,但是出现了乱码。

原因是序列化的问题。

RedisTemplate默认使用的是JdkSerializationRedisSerializer,存入数据会将数据先序列化成字节数组然后在存入Redis数据库。 

三、解决key-value乱码

解决乱码的两种方式:

1. 使用StringRedisTemplate:StringRedisTemplate 使用的是 StringRedisSerializer(存储字符串-推荐)

2. 配置RedisConfig:编写自己的 RedisTemplate 类(存储对象-推荐)

① 直接使用 StringRedisTemplate 操作 Redis 数据库

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    void contextLoads() {
        stringRedisTemplate.opsForValue().set("mykey", "DemoApplicationTests测试");
        System.out.println(stringRedisTemplate.opsForValue().get("mykey"));
    }
}

编写自己的 RedisTemplate ,更改序列化方式

@Configuration
public class RedisConfig {

    @Bean // 自己定义了一个 RedisTemplate
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        // 我们为了自己开发方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // Json序列化配置
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(om);

        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(serializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();

        return template;
    }
}

测试类:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
       redisTemplate.opsForValue().set("mykey", "DemoApplicationTests测试");
       System.out.println(redisTemplate.opsForValue().get("mykey"));
    }
}

● 测试结果

解决了 key 的乱码问题,但是 value 还是有中文乱码问题。

原因是 Redis 的 value 存储中文后,get 获取显示的是16进制的字符串

解决:启动redis-cli客户端时,在其后面加上 --raw 即可,汉字即可显示正常。

[root@redistest ~]# redis-cli --raw -p 6379

问题都解决了,key-value都可以正常显示。

四、StringRedisTemplate 与 RedisTemplate 的区别

● 两者的关系是 StringRedisTemplate 继承 RedisTemplate 。

● 两者的数据是不共通的;也就是说 StringRedisTemplate 只能管理 StringRedisTemplate 里面的数据,RedisTemplate 只能管理 RedisTemplate 中的数据。

● 其实他们两者之间的区别主要在于他们使用的序列化类:

 RedisTemplate 使用的是 JdkSerializationRedisSerializer 存入数据会将数据先序列化成字节数组然后在存入 Redis 数据库。 

 StringRedisTemplate 使用的是 StringRedisSerializer

● 使用时注意事项:

 当你的 redis 数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用 StringRedisTemplate 即可。

 但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从 Redis 里面取出一个对象,那么使用 RedisTemplate 是更好的选择。

● RedisTemplate 使用时常见问题:

 redisTemplate 中存取数据都是字节数组。当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null。可以使用 StringRedisTemplate 试试。

原文地址:https://www.cnblogs.com/Dm920/p/12885134.html