连接到Redis


使用Redis和Spring时的首要任务之一是通过IoC容器连接到Redis。为此,需要java连接器(或绑定)。无论选择哪种库,你都只需要使用一组Spring Data Redis API(在所有连接器中行为一致):org.springframework.data.redis.connection软件包及其RedisConnection与RedisConnectionFactory接口,用于处理和检索与Redis的活动连接。

RedisConnection和RedisConnectionFactory

RedisConnection提供了Redis通信和核心构建块,因为它处理与Redis后端的通信。它还会自动将基础链接库异常转换为Spring一致的DAO异常层次结构,以便您可以在不更改任何代码的情况下切换连接器,因为操作语义保持不变。

当按照上篇文档配置好Redis后,IOC会加载ConnectionFactory,我们可以直接注入,然后创建连接操作Redis。

RedisConnection提供了Redis 各大数据类型的操作API:

public interface RedisConnection extends RedisCommands, AutoCloseable {
   
     
    default RedisGeoCommands geoCommands() {
   
     
        return this;
    }
    default RedisHashCommands hashCommands() {
   
     
        return this;
    }
    default RedisHyperLogLogCommands hyperLogLogCommands() {
   
     
        return this;
    }
    default RedisKeyCommands keyCommands() {
   
     
        return this;
    }
    default RedisListCommands listCommands() {
   
     
        return this;
    }
    default RedisSetCommands setCommands() {
   
     
        return this;
    }
    default RedisScriptingCommands scriptingCommands() {
   
     
        return this;
    }
    default RedisServerCommands serverCommands() {
   
     
        return this;
    }
    default RedisStreamCommands streamCommands() {
   
     
        return this;
    }
    default RedisStringCommands stringCommands() {
   
     
        return this;
    }
    default RedisZSetCommands zSetCommands() {
   
     
        return this;
    }
}
@Autowired
    LettuceConnectionFactory lettuceConnectionFactory;

    @Test
    void lettuceConnectionFactoryTest() {
   
     
        RedisConnection connection = lettuceConnectionFactory.getConnection();
        Boolean result = connection.set("k".getBytes(), "1".getBytes());
        System.err.println(result);

        byte[] bytes = connection.get("k".getBytes());
        assert bytes != null;
        System.err.println("k:" + new String(bytes));
    }

RedisTemplate简介

大多数用户可能会使用RedisTemplate及其相应的软件包org.springframework.data.redis.core。实际上,由于模版具有丰富的功能集,因此它是Redis模块的中心类。该模板为Redis交互提供了高级抽象,虽然RedisConnection提供了接受和返回二进制值(byte数组)的低级方法,但是模板负责序列化和连接管理,使用户无需处理此类细节。

此外,该模板提供了操作视图(根据Redis命令参考进行分组),提供了丰富的,通用的接口,用于针对某种类型或某些键(通过keyBound接口),如下表所述:

界面 

描述

按键类型操作

GeoOperations

Redis的地理空间操作的,比如GEOADD,GEORADIUS...

HashOperations

Redis哈希操作

HyperLogLogOperations

Redis的HyperLogLog操作,例如PFADD,PFCONT,...

ListOperations

Redis列表操作

SetOperations

Redis设置操作

ValueOperations

Redis字符串(或值)操作

ZSetOperations

Redis zset(或排序集)操作

关键绑定操作

BoundGeoOperations

Redis键绑定地理空间操作

BoundHashOperations

Redis哈希键绑定操作

BoundKeyOperations

Redis按键绑定操作

BoundListOperations

Redis列表键绑定操作

BoundSetOperations

Redis设置键绑定操作

BoundValueOperations

Redis字符串(或值)键绑定操作

BoundZSetOperations

Redis zset(或排序集)键绑定操作

序列化器

自带序列化器

RedisTemplate大多数操作都使用基于Java的序列化器。这意味着模板编写或读取的任何对象都将通过Java进行序列化和反序列化。你可以在模板上更改序列化机制,Redis模块提供了几种实现,可在org.springframework.data.redis.serializer软件包中找到,您还可以将任何序列化器设置为null,并通过将enableDefaultSerializer属性设置为来将RedisTemplate与原始字节数组一起使用False。请注意,模板要求所有键都不为空。但是,只要基础串行器接受这些值,它们就可以为空。

从框架的角度来看,Redis中存储的数据仅为字节。尽管Redis本身支持各种类型,但在大多数情况下,它们是指数据的存储方式而不是数据的表示方式。由用户决定是否将信息转换为字符串或任何其他对象。

在Spring Data中,用户(自定义)类型和原始数据之间的转换(反之亦然)在org.springframework.data.redis.serializer包中的Redis中进行处理。

该软件包包含两种类型的序列化器,它们负责序列化过程:

  • 基于的两路串行器RedisSerializer。
  • 使用RedisElementReader和的元素读取器和写入器RedisElementWriter。

框架自带各种序列化器:

redistemplate操作map序列化_序列化

名称

说明

OxmSerializer

通过Spring OXM支持将其用于对象/XML映射

ByteArrayRedisSerializer

Byte数组序列化

GenericJackson2JsonRedisSerializer

以JSON格式去存储数据,会保存序列化的对象的包名和类名,反序列化时以这个作为标示就可以反序列化成指定的对象。效率低,占用内存高

GenericToStringSerializer

可以将任何对象泛化为字符串并序列化

StringRedisSerializer

简单的字符串序列化

JdkSerializationRedisSerializer

JDK序列化,默认用于RedisCache和RedisTemplate

Jackson2JsonRedisSerializer

以JSON格式去存储数据,需要指明序列化的类Class,可以使用Object.class

自定义序列化器

RedisTemplate默认使用JDK序列化,可以使用自带其他的序列化,或者自己实现第三方序列化方式,比如:

  • google:Protobuf
  • faceBook:Thrift
  • kryo
  • hessian
  • fst
  • Jackson
  • Gson
  • FastJson
Protobuf序列化

ProtoBuf(Google Protocol Buffer)是由Google公司用于数据交换的序列结构化数据格式,具有跨平台、跨语言、可扩展特性,类型于常用的XML及JSON,但具有更小的传输体积、更高的编码、编码能力,特别适合于数据存储、网络数据传输等对存储体积、实时性要求高的领域。

优点:性能好,效率高。支持向后兼容和向前兼容。支持多种编程语言(Java,C++,python);

缺点:二进制格式导致可读性差(二进制格式)

RedisTemplate使用Protobuf

1、添加POM;

<dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>1.7.4</version>
        </dependency>
        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>1.7.4</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

1、 实现RedisSerializer接口;

@Slf4j
public class ProtoStuffRedisSerializer<T> implements RedisSerializer<T> {
   
     

    // RuntimeSchema是一个包含业务对象所有信息的类,包括类信息、字段信息
    private static final Schema<ProtoStuffWrapper> schema = RuntimeSchema.getSchema(ProtoStuffWrapper.class);

    /**
     * 序列化:对象=》字节数组
     *
     * @param t 需要序列化的对象t
     * @return 二进制
     * @throws SerializationException 序列化异常
     */
    @Override
    public byte[] serialize(T t) throws SerializationException {
   
     
        if (t == null) {
   
     
            return null;
        }
        // 开辟了512字节缓存,用来存放业务对象序列化之后存放的地方,如果空间不足,会自动扩展扩展
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        byte[] bytes;
        try {
   
     
            // 序列化
            bytes = ProtostuffIOUtil.toByteArray(new ProtoStuffWrapper<>(t), schema, buffer);
        } finally {
   
     
            buffer.clear();
        }
        return bytes;
    }

    /**
     * 反序列化 字节数组=》对象
     *
     * @param bytes 字节数组
     * @return 对象
     * @throws SerializationException 序列化异常
     */
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
   
     
        if (bytes == null || bytes.length == 0) {
   
     
            return null;
        }
        try {
   
     
            ProtoStuffWrapper<T> protoStuffWrapper = new ProtoStuffWrapper<>();
            // 反序列
            ProtostuffIOUtil.mergeFrom(bytes, protoStuffWrapper, schema);
            return protoStuffWrapper.getT();
        } catch (Exception e) {
   
     
            throw new RuntimeException(e);
        }
    }

    /**
     * 序列化包装类,深度克隆,避免无法获取schema
     *
     * @param <T> 业务对象
     */
    public static class ProtoStuffWrapper<T> implements Cloneable {
   
     
        private T t;

        ProtoStuffWrapper() {
   
     
        }

        ProtoStuffWrapper(T t) {
   
     
            this.t = t;
        }

        public T getT() {
   
     
            return t;
        }

        public void setT(T t) {
   
     
            this.t = t;
        }

        @Override
        @SuppressWarnings("unchecked")
        public ProtoStuffWrapper<T> clone() {
   
     
            try {
   
     
                return (ProtoStuffWrapper<T>) super.clone();
            } catch (CloneNotSupportedException e) {
   
     
                return new ProtoStuffWrapper<T>();
            }
        }
    }
}

1、 创建RedisTemplate,设置序列化;

/**
     * 创建RedisTemplate
     *
     * @param redisConnectionFactory 连接工厂
     * @param <T>                    值类型
     * @return RedisTemplate
     */
    @Bean(name = "redisTemplate")
    public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
   
     
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
        // 设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // String序列化对象
        RedisSerializer<String> stringRedisSerializer = RedisSerializer.string();
        // ProtoStuff序列化
        ProtoStuffRedisSerializer<T> protoStuffRedisSerializer = new ProtoStuffRedisSerializer<>();
        // 序列化配置=>Key
        redisTemplate.setKeySerializer(stringRedisSerializer); // 所有Key都设置为字符串,方便阅读
        redisTemplate.setHashKeySerializer(protoStuffRedisSerializer); //  设置Hash数据结构中的Key
        // 序列化配置=>Value
        redisTemplate.setValueSerializer(protoStuffRedisSerializer); // 所有Value
        redisTemplate.setHashValueSerializer(protoStuffRedisSerializer);  //  Hash数据结构中的Value
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

1、 添加测试实体类;

@ToString
@Data
public class User {
   
     
    String userName;
    String password;
    int age;
}

1、 添加测试类测试;

@Test
    void protoStuffTest() {
   
     
        User user = new User();
        user.setAge(20);
        user.setUserName("韩梅梅");
        user.setPassword("123456");

        redisTemplate.boundValueOps("k").set(user);
        User user1 = redisTemplate.boundValueOps("k").get();

        redisTemplate.boundHashOps("hash").putIfAbsent("kkk","vvv");
        System.err.println(user1.toString());
    }

redistemplate操作map序列化_缓存_02