深入浅出springboot--redis的整合(1)

这里我们不在详细的介绍redis的相关信息,redis是一个非关系型数据库。redis是基于内存进行存储的,存储速度非常快,是关系型数据库的几倍到几十倍,可以1s内完成10万次的读写,适用于查询情况多的网站,用于提升性能。除次之外,redis还提供了简单的事务机制,保证高并发场景下的数据的一致性。
redis的数据结构有字符串,列表,散列(hash),集合,有序集合,基数和地理位置。这里我们主要讨论前五种数据结构。在引入redis的时候我们通常是使用jedis来进行对其的操作,因此需要排除lettuce,导入redis。

  • pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiyou</groupId>
    <artifactId>spring-redis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.13.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

    </dependencies>
</project>

spring和redis的整合

spring提供了RedisConnectionFactory接口。该接口可以生成一个RedisConnection接口对象,而RedisConnection接口对象是对Redis底层接口的封装。

  • redis的常用接口和类:

(1) RedisConnectionFactory:
该接口是一个工厂,主要是用来配置Redis的连接池,可以设定其最大的连接数,超时时间等属性
(2)RedisConnection:
是一个接口,该接口是redis的连接池,用来生成redis对象
(3)AbstractRedisConnection:
是一个抽象类,实现了RedisConnection
(4)JedisConnection:
实体类,集成子AbstractRedisConnection,用来封装Jedis的相关操作
(5)RedisClusterConnection:
接口,实现了RedisConnection
(6)JedisClusterConnection:
实体类,实现了RedisClusterConnection,用来对集群的支持
(7)StringRedisConnection:
接口,实现了RedisConnection
(8)DefaultStringRedisConnection:
实体类,实现了StringRedisConnection,是对字符串的支持


代码如下:
下面的代码不止生成了一个Redis的工厂(RedisConnectionFactory),还提供了redisTemplate。
RedisTemplate是一个强大的类,他会自己从RedisConnectionFactory中获取连接,然后执行对应的Redis命令,在最后还会自动关闭redis的连接,这些都是redisTemplate的自动封装的。

  • redis的配置类,负责生成RedisConnectionFactory和redisTemplate负责操作redis
package com.xiyou.redis.utils;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.JedisPoolConfig;

/**
 * reidis的配置类,负责生成connectionFactory
 */
@Configuration
public class RedisConfig {
    // 存取redisConnectionFactory
    private RedisConnectionFactory connectionFactory;

    /**
     * 创建redisConnectionFactory的对象
     * @return
     */
    @Bean("redisConnectionFactory")
    public RedisConnectionFactory initRedisConnectionFactory(){
        // connectionFactory只用一个对象就行,所以如果该对象有值,不再继续执行
        if(connectionFactory != null){
            return connectionFactory;
        }
        // 创建配置类对象
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        // 最大的空闲数
        poolConfig.setMaxIdle(30);
        // 最大的连接数
        poolConfig.setMaxTotal(50);
        // 最大的等待毫秒数
        poolConfig.setMaxWaitMillis(2000);
        // 创建Jedis的工厂
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.setHostName("127.0.0.1");
        jedisConnectionFactory.setPort(6379);
        connectionFactory = jedisConnectionFactory;
        return connectionFactory;
    }

    /**
     * 生成redisTemplate对象,用来操作redis
     * @return
     */
    @Bean("redisTemplate")
    public RedisTemplate<Object, Object> initRedisTemplate(){
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(initRedisConnectionFactory());
        return redisTemplate;
    }

}


  • 测试操作:
package com.xiyou.redis.test;

import com.xiyou.redis.utils.RedisConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * redis的测试
 */
public class RedisTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RedisConfig.class);
        RedisTemplate<Object, Object> redisTemplate = applicationContext.getBean(RedisTemplate.class);
        // 操作string类型
        redisTemplate.opsForValue().set("key1", "value1");
        redisTemplate.opsForHash().put("hash", "field", "hvalue");
    }
}


  • 运行结果(此时会有两个待优化的点)

在这里插入图片描述

通过上面的结果我们可以看到redis已经保存成功,但是他的结果保存出来我们并不认识,这是为什么呢??
其原因就是Redis是一种基于字符串进行存储的NoSQL,而Java是基于对象的语言,对象是无法存储到redis中的,不过java提供了序列化的机制,只需要实现Serializable接口,这就代表了类的对象可以进行序列化,序列化后我们就可以用redis对其进行存储。但是我们通常看不懂java序列化后的结果。
具体如何修改呢?请往下看,我来揭晓


在这里插入图片描述

可以看到我们上述的操作有两个步骤操作redis,一个是字符串,一个是hash操作,此时我们看打印,发现分别打开了两个链接,操作了一个redis,关闭连接,然后再一次开启,继续操作再关闭,那么这种操作就有点不舒服了,浪费了资源,如果我们想在一个redis连接下操作应该如何做呢?继续看。


  • 解决redis的存储序列化问题:

  • spring关于Redis的序列化器设置
    在这里插入图片描述
    一般我们默认的序列化器是JdkSerializationRedisSerializer,就是说如果我们没有显示的指出序列化器的时候,我们就会用该序列化器,我们之前的redis存储的看不懂的就是这个序列化器序列化的,我们通常使用的是StringRedisSerializer序列化器。
    通常序列化器有两个方法:
    (1)serialize
    序列化方法,将对象变为字符串
    (2)deserialize
    反序列化,将字符串转为对象
    其原理图:
    在这里插入图片描述
  • redisTemplate的序列化器属性

redisTemplate会自动初始化StringRedisSerializer,所以我们若想获取该序列化器可以直接获取

RedisSerializer stringRedisSerializer = redisTemplate.getStringSerializer();

获取成功后,我们需要给其设置相关属性

属性描述备注
defaultSerializer默认的序列化器如果没有设置,则默认使用JdkSerializationRedisSerializer
keySerializerRedis的键序列化器如果没有设置,则使用默认序列化器
valueSerializerRedis的值序列化器如果没有设置,则使用默认序列化器
hashKeySerializerRedis散列结构的field序列化器如果没有设置,则使用默认序列化器
hashValueSerializerRedis散列结构的value序列化器如果没有设置,则使用默认序列化器
stringSerializer字符串序列化器RedisTemplate自动赋值为StringRedisSerializer对象
  • 修改redis的配置
    在生成redisTemplate的时候指明序列化器
    /**
     * 生成redisTemplate对象,用来操作redis
     * @return
     */
    @Bean("redisTemplate")
    public RedisTemplate<Object, Object> initRedisTemplate(){
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(initRedisConnectionFactory());
        // 设置字符串序列化器,让存储在redis中的代码我们可以看明白
        // 1. 得到字符串序列化器,将其解析成字符串的形式
        // **redisTemplate会自动初始化StringRedisSeriaizer,所以这里可以直接获取**
        RedisSerializer stringRedisSerializer = redisTemplate.getStringSerializer();
        // 设置key的序列化器
        redisTemplate.setKeySerializer(stringRedisSerializer);
        // 设置value的序列化器
        redisTemplate.setValueSerializer(stringRedisSerializer);
        // 设置hash的key的序列化器
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        // 设置hash的value的序列化器
        redisTemplate.setHashValueSerializer(stringRedisSerializer);
        return redisTemplate;
    }

其他代码不做改变,结果如下
在这里插入图片描述


  • 解决redis的每一次操作,打开一个连接的问题:

我们redis的两个赋值操作都不是在一个redis的连接中完成的,这样是在浪费资源,Spring为我们提供了RedisCallback和SessionCallback两个接口,他们的作用是让RedisTemplate进行回调,通过他们可以在同一条连接下执行多个Redis命令。
其中sessionCallback提供了良好的封装,对于开发者比较友好,因此在实际的开发中应该优先使用;RedisCallback接口比较底层,需要处理的内容比较多,可读性较差,所以非必要的时候尽量不要选择他。

  • 修改测试类的代码。新增方法
    /**
     * 使用sessionCallback转换规则,较为简单 推荐使用
     * @param redisTemplate
     */
    public void useSessionCallback(RedisTemplate redisTemplate){
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.opsForValue().set("keyCall", "valueCall");
                redisOperations.opsForHash().put("hashCall", "fieldCall", "valueCall");
                return null;
            }
        });
    }

    /**
     * 使用redisCallBack转换规则,较为负责,尽量不要使用,可以改写底层
     * @param redisTemplate
     */
    public void useRedisCallBack(RedisTemplate redisTemplate){
        redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                redisConnection.set("redisKey".getBytes(), "valueRedis".getBytes());
                redisConnection.hSet("hashRedis".getBytes(), "fieldRedis".getBytes(), "hRedis".getBytes());
                return null;
            }
        });
    }
  • 运行结果
    在这里插入图片描述
    通过上面的结果可以看到,我们操作了两条redis的记录,只是开启了一个redis连接。操作完成后,redis自动关闭了连接
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值