当前位置: 首页 > article >正文

RedisTemplate的配置和讲解以及和StringRedisTemplate的区别

本文主要讲redisTempalte的几种常用的序列化方式

  • string,我们大部分情况下都希望存入redis的数据可读性强一些,并且value也不总是一个规则的类型,所以这里也是不用json序列化的原因,可以更自由方便,下边提供配置方法
    package sca.pro.core.redis.configuration;
    
    import cn.hutool.core.convert.Convert;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisPassword;
    import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.time.Duration;
    
    @Configuration
    @EnableCaching
    public class RedisTemplateConfig {
        @Value("${spring.redis.database}")
        private int database;
    
        @Value("${spring.redis.host}")
        private String host;
    
        @Value("${spring.redis.password}")
        private String password;
    
        @Value("${spring.redis.port}")
        private String port;
    
        @Value("${spring.redis.timeout}")
        private String timeout;
    
        @Value("${spring.redis.lettuce.pool.max-idle}")
        private String maxIdle;
    
        @Value("${spring.redis.lettuce.pool.min-idle}")
        private String minIdle;
    
        @Value("${spring.redis.lettuce.pool.max-active}")
        private String maxActive;
    
        @Value("${spring.redis.lettuce.pool.max-wait}")
        private String maxWait;
    
        @Bean
        public LettuceConnectionFactory lettuceConnectionFactory() {
            GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
            genericObjectPoolConfig.setMaxIdle(Convert.toInt(maxIdle));
            genericObjectPoolConfig.setMinIdle(Convert.toInt(minIdle));
            genericObjectPoolConfig.setMaxTotal(Convert.toInt(maxActive));
            genericObjectPoolConfig.setMaxWaitMillis(Convert.toLong(maxWait));
            genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(100);
            RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
            redisStandaloneConfiguration.setDatabase(database);
            redisStandaloneConfiguration.setHostName(host);
            redisStandaloneConfiguration.setPort(Convert.toInt(port));
            redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
            LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                    .commandTimeout(Duration.ofMillis(Convert.toLong(timeout)))
                    .poolConfig(genericObjectPoolConfig)
                    .build();
    
            LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
            return factory;
        }
    
        @Bean
        public RedisTemplate<String, String> redisTemplate(LettuceConnectionFactory factory) {
            // 配置redisTemplate
            RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(factory);
            redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
            redisTemplate.setValueSerializer(new StringRedisSerializer());//value序列化
            //设置hash的key的序列化方式
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            //设置hash的value的序列化方式
            redisTemplate.setHashValueSerializer(new StringRedisSerializer());
            redisTemplate.afterPropertiesSet();//使上面参数生效
            return redisTemplate;
        }
    }
    

其实如果key和value都是string,那就等效于我们直接引入StringRedisTemplate 

  • 如果使用字节数组的形式序列化,redistemplate默认使用的jdk的序列化方式,但是jdk的序列化后的字节数组不仅重,而且序列化和反序列化我们用的是protobuf,如下

   pom

<!-- 工具库 -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>
 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- 序列化 -->
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.1.3</version>
</dependency>
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.1.3</version>
</dependency>

2.自己编写序列化工具

@Slf4j
public class ProtoStuffUtil {
    /**
     * 序列化对象
     *
     * @param obj
     * @return
     */
    public static <T> byte[] serialize(T obj) {
        if (obj == null) {
            log.error("Failed to serializer, obj is null");
            throw new RuntimeException("Failed to serializer");
        }
 
        @SuppressWarnings("unchecked") Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(obj.getClass());
        LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
        byte[] protoStuff;
        try {
            protoStuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            log.error("Failed to serializer, obj:{}", obj, e);
            throw new RuntimeException("Failed to serializer");
        } finally {
            buffer.clear();
        }
        return protoStuff;
    }
 
    /**
     * 反序列化对象
     *
     * @param paramArrayOfByte
     * @param targetClass
     * @return
     */
    public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
        if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
            log.error("Failed to deserialize, byte is empty");
            throw new RuntimeException("Failed to deserialize");
        }
 
        T instance;
        try {
            instance = targetClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            log.error("Failed to deserialize", e);
            throw new RuntimeException("Failed to deserialize");
        }
 
        Schema<T> schema = RuntimeSchema.getSchema(targetClass);
        ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
        return instance;
    }
 
    /**
     * 序列化列表
     *
     * @param objList
     * @return
     */
    public static <T> byte[] serializeList(List<T> objList) {
        if (objList == null || objList.isEmpty()) {
            log.error("Failed to serializer, objList is empty");
            throw new RuntimeException("Failed to serializer");
        }
 
        @SuppressWarnings("unchecked") Schema<T> schema =
                (Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass());
        LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
        byte[] protoStuff;
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
            protoStuff = bos.toByteArray();
        } catch (Exception e) {
            log.error("Failed to serializer, obj list:{}", objList, e);
            throw new RuntimeException("Failed to serializer");
        } finally {
            buffer.clear();
            try {
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
 
        return protoStuff;
    }
 
    /**
     * 反序列化列表
     *
     * @param paramArrayOfByte
     * @param targetClass
     * @return
     */
    public static <T> List<T> deserializeList(byte[] paramArrayOfByte, Class<T> targetClass) {
        if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
            log.error("Failed to deserialize, byte is empty");
            throw new RuntimeException("Failed to deserialize");
        }
 
        Schema<T> schema = RuntimeSchema.getSchema(targetClass);
        List<T> result;
        try {
            result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema);
        } catch (IOException e) {
            log.error("Failed to deserialize", e);
            throw new RuntimeException("Failed to deserialize");
        }
        return result;
    }
 
}

3.RedisTemplate的工具类方法

@Component
public class RedisClient {
    private final RedisTemplate<String, String> redisTemplate;
 
    @Autowired
    public RedisClient(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
 
    /**
     * get cache
     *
     * @param field
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> T get(final String field, Class<T> targetClass) {
        byte[] result = redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.get(field.getBytes()));
        if (result == null) {
            return null;
        }
 
        return ProtoStuffUtil.deserialize(result, targetClass);
    }
 
    /**
     * put cache
     *
     * @param field
     * @param obj
     * @param <T>
     * @return
     */
    public <T> void set(String field, T obj) {
        final byte[] value = ProtoStuffUtil.serialize(obj);
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.set(field.getBytes(), value);
            return null;
        });
    }
 
    /**
     * put cache with expire time
     *
     * @param field
     * @param obj
     * @param expireTime 单位: s
     * @param <T>
     */
    public <T> void setWithExpire(String field, T obj, final long expireTime) {
        final byte[] value = ProtoStuffUtil.serialize(obj);
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.setEx(field.getBytes(), expireTime, value);
            return null;
        });
    }
 
    /**
     * get list cache
     *
     * @param field
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> List<T> getList(final String field, Class<T> targetClass) {
        byte[] result = redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.get(field.getBytes()));
        if (result == null) {
            return null;
        }
 
        return ProtoStuffUtil.deserializeList(result, targetClass);
    }
 
    /**
     * put list cache
     *
     * @param field
     * @param objList
     * @param <T>
     * @return
     */
    public <T> void setList(String field, List<T> objList) {
        final byte[] value = ProtoStuffUtil.serializeList(objList);
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.set(field.getBytes(), value);
            return null;
        });
    }
 
    /**
     * put list cache with expire time
     *
     * @param field
     * @param objList
     * @param expireTime
     * @param <T>
     * @return
     */
    public <T> void setListWithExpire(String field, List<T> objList, final long expireTime) {
        final byte[] value = ProtoStuffUtil.serializeList(objList);
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.setEx(field.getBytes(), expireTime, value);
            return null;
        });
    }
 
    /**
     * get h cache
     *
     * @param key
     * @param field
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> T hGet(final String key, final String field, Class<T> targetClass) {
        byte[] result = redisTemplate
                .execute((RedisCallback<byte[]>) connection -> connection.hGet(key.getBytes(), field.getBytes()));
        if (result == null) {
            return null;
        }
 
        return ProtoStuffUtil.deserialize(result, targetClass);
    }
 
    /**
     * put hash cache
     *
     * @param key
     * @param field
     * @param obj
     * @param <T>
     * @return
     */
    public <T> boolean hSet(String key, String field, T obj) {
        final byte[] value = ProtoStuffUtil.serialize(obj);
        return redisTemplate.execute(
                (RedisCallback<Boolean>) connection -> connection.hSet(key.getBytes(), field.getBytes(), value));
    }
 
    /**
     * put hash cache
     *
     * @param key
     * @param field
     * @param obj
     * @param <T>
     */
    public <T> void hSetWithExpire(String key, String field, T obj, long expireTime) {
        final byte[] value = ProtoStuffUtil.serialize(obj);
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.hSet(key.getBytes(), field.getBytes(), value);
            connection.expire(key.getBytes(), expireTime);
            return null;
        });
    }
 
    /**
     * get list cache
     *
     * @param key
     * @param field
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> List<T> hGetList(final String key, final String field, Class<T> targetClass) {
        byte[] result = redisTemplate
                .execute((RedisCallback<byte[]>) connection -> connection.hGet(key.getBytes(), field.getBytes()));
        if (result == null) {
            return null;
        }
 
        return ProtoStuffUtil.deserializeList(result, targetClass);
    }
 
    /**
     * put list cache
     *
     * @param key
     * @param field
     * @param objList
     * @param <T>
     * @return
     */
    public <T> boolean hSetList(String key, String field, List<T> objList) {
        final byte[] value = ProtoStuffUtil.serializeList(objList);
        return redisTemplate.execute(
                (RedisCallback<Boolean>) connection -> connection.hSet(key.getBytes(), field.getBytes(), value));
    }
 
    /**
     * get cache by keys
     *
     * @param key
     * @param fields
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> Map<String, T> hMGet(String key, Collection<String> fields, Class<T> targetClass) {
        List<byte[]> byteFields = fields.stream().map(String::getBytes).collect(Collectors.toList());
        byte[][] queryFields = new byte[byteFields.size()][];
        byteFields.toArray(queryFields);
        List<byte[]> cache = redisTemplate
                .execute((RedisCallback<List<byte[]>>) connection -> connection.hMGet(key.getBytes(), queryFields));
 
        Map<String, T> results = new HashMap<>(16);
        Iterator<String> it = fields.iterator();
        int index = 0;
        while (it.hasNext()) {
            String k = it.next();
            if (cache.get(index) == null) {
                index++;
                continue;
            }
 
            results.put(k, ProtoStuffUtil.deserialize(cache.get(index), targetClass));
            index++;
        }
 
        return results;
    }
 
    /**
     * set cache by keys
     *
     * @param field
     * @param values
     * @param <T>
     */
    public <T> void hMSet(String field, Map<String, T> values) {
        Map<byte[], byte[]> byteValues = new HashMap<>(16);
        for (Map.Entry<String, T> value : values.entrySet()) {
            byteValues.put(value.getKey().getBytes(), ProtoStuffUtil.serialize(value.getValue()));
        }
 
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            connection.hMSet(field.getBytes(), byteValues);
            return null;
        });
    }
 
    /**
     * get caches in hash
     *
     * @param key
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> Map<String, T> hGetAll(String key, Class<T> targetClass) {
        Map<byte[], byte[]> records = redisTemplate
                .execute((RedisCallback<Map<byte[], byte[]>>) connection -> connection.hGetAll(key.getBytes()));
 
        Map<String, T> ret = new HashMap<>(16);
        for (Map.Entry<byte[], byte[]> record : records.entrySet()) {
            T obj = ProtoStuffUtil.deserialize(record.getValue(), targetClass);
            ret.put(new String(record.getKey()), obj);
        }
 
        return ret;
    }
 
    /**
     * list index
     *
     * @param key
     * @param index
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> T lIndex(String key, int index, Class<T> targetClass) {
        byte[] value =
                redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.lIndex(key.getBytes(), index));
        return ProtoStuffUtil.deserialize(value, targetClass);
    }
 
    /**
     * list range
     *
     * @param key
     * @param start
     * @param end
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> List<T> lRange(String key, int start, int end, Class<T> targetClass) {
        List<byte[]> value = redisTemplate
                .execute((RedisCallback<List<byte[]>>) connection -> connection.lRange(key.getBytes(), start, end));
        return value.stream().map(record -> ProtoStuffUtil.deserialize(record, targetClass))
                .collect(Collectors.toList());
    }
 
    /**
     * list left push
     *
     * @param key
     * @param obj
     * @param <T>
     */
    public <T> void lPush(String key, T obj) {
        final byte[] value = ProtoStuffUtil.serialize(obj);
        redisTemplate.execute((RedisCallback<Long>) connection -> connection.lPush(key.getBytes(), value));
    }
 
    /**
     * list left push
     *
     * @param key
     * @param objList
     * @param <T>
     */
    public <T> void lPush(String key, List<T> objList) {
        List<byte[]> byteFields = objList.stream().map(ProtoStuffUtil::serialize).collect(Collectors.toList());
        byte[][] values = new byte[byteFields.size()][];
 
        redisTemplate.execute((RedisCallback<Long>) connection -> connection.lPush(key.getBytes(), values));
    }
 
    /**
     * 精确删除key
     *
     * @param key
     */
    public void deleteCache(String key) {
        redisTemplate.delete(key);
    }
 
 
    /**
     * 排行榜的存入
     *
     * @param redisKey
     * @param immutablePair
     */
    public void zAdd(String redisKey, ImmutablePair<String, BigDecimal> immutablePair) {
        final byte[] key = redisKey.getBytes();
        final byte[] value = immutablePair.getLeft().getBytes();
        redisTemplate.execute((RedisCallback<Boolean>) connection -> connection
                .zAdd(key, immutablePair.getRight().doubleValue(), value));
 
    }
 
    /**
     * 获取排行榜低->高排序
     *
     * @param redisKey 要进行排序的类别
     * @param start
     * @param end
     * @return
     */
    public List<ImmutablePair<String, BigDecimal>> zRangeWithScores(String redisKey, int start, int end) {
        Set<RedisZSetCommands.Tuple> items = redisTemplate.execute(
                (RedisCallback<Set<RedisZSetCommands.Tuple>>) connection -> connection
                        .zRangeWithScores(redisKey.getBytes(), start, end));
        return items.stream()
                .map(record -> ImmutablePair.of(new String(record.getValue()), BigDecimal.valueOf(record.getScore())))
                .collect(Collectors.toList());
    }
 
 
    /**
     * 获取排行榜高->低排序
     *
     * @param redisKey 要进行排序的类别
     * @param start
     * @param end
     * @return
     */
    public List<ImmutablePair<String, BigDecimal>> zRevRangeWithScores(String redisKey, int start, int end) {
        Set<RedisZSetCommands.Tuple> items = redisTemplate.execute(
                (RedisCallback<Set<RedisZSetCommands.Tuple>>) connection -> connection
                        .zRevRangeWithScores(redisKey.getBytes(), start, end));
        return items.stream()
                .map(record -> ImmutablePair.of(new String(record.getValue()), BigDecimal.valueOf(record.getScore())))
                .collect(Collectors.toList());
    }
}
 
  • 最推荐的一种序列化方式GenericJackson2JsonRedisSerializer,org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer 使用Jackson 实现JSON的序列化方式,Generic单词翻译过来表示:通用的意思,可以看出,是支持所有类。

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
 
        //String的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 使用GenericJackson2JsonRedisSerializer 替换默认序列化(默认采用的是JDK序列化)
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
 
        //key序列化方式采用String类型
        template.setKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson类型
        template.setValueSerializer(genericJackson2JsonRedisSerializer);
        //hash的key序列化方式也是采用String类型
        template.setHashKeySerializer(stringRedisSerializer);
        //hash的value也是采用jackson类型
        template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

}

运行下边的测试类测试GenericJackson2JsonRedisSerializer,发现不管是字符串还是对象还是数组都很通用

@Test
void redisTemplateSerializeTest() {
    String redisTemplateStringKey = "redisTemplateStringKey";
    String redisTemplateUserObjectKey = "redisTemplateUserObjectKey";
    String redisTemplateUserArrayObjectKey = "redisTemplateUserArrayObjectKey";
    String redisTemplateJSONObjectKey = "redisTemplateJSONObjectKey";
    String redisTemplateJSONArrayKey = "redisTemplateJSONArrayKey";
 
    //序列化String类型和反序列化String类型
    redisTemplate.opsForValue().set(redisTemplateStringKey, "austin");
    String austin = (String) redisTemplate.opsForValue().get(redisTemplateStringKey);
    System.out.println("stringGet: " + austin);
 
    //序列化Object对象类型和反序列化Object对象类型 (User对象)
    User user = new User("123", "austin", 25);
    redisTemplate.opsForValue().set(redisTemplateUserObjectKey, user);
    User userGet = (User) redisTemplate.opsForValue().get(redisTemplateUserObjectKey);
    System.out.println("userGet: " + userGet);
 
    //序列化Object对象数组类型和反序列化Object对象数组类型 (User[]对象数组)
    User user1 = new User("1", "austin1", 25);
    User user2 = new User("2", "austin2", 25);
    User[] userArray = new User[]{user1, user2};
    redisTemplate.opsForValue().set(redisTemplateUserArrayObjectKey, userArray);
    User[] userArrayGet = (User[]) redisTemplate.opsForValue().get(redisTemplateUserArrayObjectKey);
    System.out.println("userArrayGet: " + userArrayGet);
 
    //序列化JSONObject对象类型和反序列化JSONObject对象类型
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("id", "123");
    jsonObject.put("name", "austin");
    jsonObject.put("age", 25);
    redisTemplate.opsForValue().set(redisTemplateJSONObjectKey, jsonObject);
    JSONObject jsonObjectGet = (JSONObject) redisTemplate.opsForValue().get(redisTemplateJSONObjectKey);
    System.out.println("jsonObjectGet: " + jsonObjectGet);
 
    //序列化JSONArray对象类型和反序列化JSONArray对象类型
    JSONArray jsonArray = new JSONArray();
    JSONObject jsonObject1 = new JSONObject();
    jsonObject1.put("id", "1");
    jsonObject1.put("name", "austin1");
    jsonObject1.put("age", 25);
    JSONObject jsonObject2 = new JSONObject();
    jsonObject2.put("id", "1");
    jsonObject2.put("name", "austin2");
    jsonObject2.put("age", 25);
    jsonArray.add(jsonObject1);
    jsonArray.add(jsonObject2);
    redisTemplate.opsForValue().set(redisTemplateJSONArrayKey, jsonArray);
    JSONArray jsonArrayGet = (JSONArray) redisTemplate.opsForValue().get(redisTemplateJSONArrayKey);
    System.out.println("jsonArrayGet: " + jsonArrayGet);
}

key- value :

字符串类型
Key: redisTemplateStringKey
Value: "austin"


对象类型
Key: redisTemplateUserObjectKey
Value:
{
    "@class": "com.example.jedisserializefrombytestojson.User",
    "id": "123",
    "name": "austin",
    "age": 25
}
 
对象数组类型
Key: redisTemplateUserArrayObjectKey
Value: 
[
    "[Lcom.example.jedisserializefrombytestojson.User;",
    [
        {
            "@class": "com.example.jedisserializefrombytestojson.User",
            "id": "1",
            "name": "austin1",
            "age": 25
        },
        {
            "@class": "com.example.jedisserializefrombytestojson.User",
            "id": "2",
            "name": "austin2",
            "age": 25
        }
    ]
]
 

JSONObject类型
Key: redisTemplateJSONObjectKey
Value:
{
    "@class": "com.alibaba.fastjson.JSONObject",
    "name": "austin",
    "id": "123",
    "age": 25
}


JSONArray类型
Key: redisTemplateJSONArrayKey
Value: 
[
    "com.alibaba.fastjson.JSONArray",
    [
        {
            "@class": "com.alibaba.fastjson.JSONObject",
            "name": "austin1",
            "id": "1",
            "age": 25
        },
        {
            "@class": "com.alibaba.fastjson.JSONObject",
            "name": "austin2",
            "id": "1",
            "age": 25
        }
    ]
]


http://www.kler.cn/a/155598.html

相关文章:

  • Springboot 启动端口占用如何解决
  • [Docker#8] 容器配置 | Mysql | Redis | C++ | 资源控制 | 命令对比
  • 前端知识点---Javascript的对象(Javascript)
  • Qt 获取当前系统中连接的所有USB设备的信息 libudev版
  • 解决:WSL2可视化opencv和pyqt冲突:QObject::moveToThread
  • uniapp 设置安全区域
  • 分享一个国内可用的免费AI-GPT网站
  • PHP字符串面试题
  • c语言-归并排序
  • 网页表格复制器(油猴插件脚本)
  • 飞天使-elk搭建补充
  • ubuntu下快速搭建docker环境训练yolov5数据集
  • 【栈和队列(2)】
  • 破解app思路
  • 数据结构和算法-哈夫曼树以相关代码实现
  • 软件工程单选多选补充
  • 运维 | 关于IP网络相关的概念和原理
  • 第16届中国R会议暨2023X-AGI大会开幕,和鲸科技分享ModelOps在数据科学平台中的实践与应用
  • QT Day01 qt概述,创建项目,窗口属性,按钮,信号与槽
  • ES6 Promise的用法,async/await异步处理同步化
  • JOSEF电流继电器 DL-33 整定范围0.5-2A 柜内安装板前接线
  • CAP BASE理论
  • Fisher信息理论与应用
  • 速速收藏!纯C实现的MD5哈希校验算法~!
  • VSCode修改C++版本
  • LoRaWAN协议栈LoRaMac-Node版本变迁历史(最新4.7.0)