简介

关系​:StringRedisTemplate继承RedisTemplate。

数据不通用​:StringRedisTemplate只能管理StringRedisTemplate的数据,RedisTemplate只能管理RedisTemplate的数据。

区别

       RedisTemplate:使用JdkSerializationRedisSerializer,存时先将数据先序列化成字节数组再存入Redis。 

       StringRedisTemplate:使用StringRedisSerializer,存时先将数据先序列化成字符串再存入Redis。

使用场景

        StringRedisTemplate:Redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型。

        RedisTemplate:数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象。

RedisTemplate使用时常见问题

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

RedisTemplate

序列化

针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)

Redis编程--RedisTemplate与StringRedisTemplate_redis

简介

使用场景

优点

缺点

JdkSerializationRedisSerializer

JDK序列化(默认)

用于对象的存取

简单

存储的为二进制数据,可读性差,占空间大。

StringRedisSerializer

“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装


1.key或value为字符串

2.数据要被工具解析


最轻量和高效

Jackson2JsonRedisSerializer

javabean与json之间的转换

将对象转成json存在redis中,也可将json转成对象

GenericJackson2JsonRedisSerializer

javabean与json之间的转换。与Jackson2JsonRedisSerializer的不同:会带包全路径,转为通用类型

OxmSerializer


javabean与xml之间的转换。

目前可用的三方:jaxb,apache-xmlbeans


编程将会有些难度,而且效率最低

指定序列化的方法

package com.example.demo.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisTemplateConfig {

@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);

// 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域:field、get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 1.指定序列化输入的类型,序列化时将对象全类名一起保存下来,便于以后进行反序列化
// 2.类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //老写法

jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}

这样:自己注入RedisTemplate进行操作时,就会使用上边的配置了。 

 注意:如果配置spring-session使用json,上边这种是不可以的,需要这样写:

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisCacheConfig {
// 将spring session中的序列化器替换成json
@Bean
public RedisSerializer springSessionDefaultRedisSerializer() {
return RedisSerializer.json();
//等价于:return new GenericJackson2JsonRedisSerializer();
}

// 将spring cache中的序列化器替换成json
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
//等价于:return RedisCacheConfiguration.defaultCacheConfig()
// .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}

方法

其他网址

​RedisTemplate常用集合使用说明(一) - - ITeye博客​

​【深入浅出SpringBoot】RedisTemplate使用方法归纳 - 简书​

Key类型操作


接口



描述


获取方法


ValueOperations



操作Redis String(或者Value)类型数据。


redisTemplate.opsForValue();


ListOperations



操作Redis List类型数据


redisTemplate.opsForList();


SetOperations



操作Redis Set类型数据


redisTemplate.opsForSet();


ZSetOperations



操作Redis ZSet(或者Sorted Set)类型数据


redisTemplate.opsForZSet();


HashOperations



操作Redis Hash类型数据


redisTemplate.opsForHash();


HyperLogLogOperations



操作Redis HyperLogLog类型数据,比如:pfadd,pfcount,...



GeoOperations



操作Redis Geospatial类型数据,比如:GEOADD,GEORADIUS,…)


Key绑定操作

可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key


接口



描述



BoundValueOperations



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



BoundListOperations



Redis列表键绑定操作



BoundSetOperations 



Redis Set键绑定操作



BoundZSetOperations



Redis ZSet(或Sorted Set)键绑定操作



BoundHashOperations



Redis Hash键绑定操作



BoundGeoOperations



Redis Geospatial 键绑定操作


基本操作

其他网址


以下所有操作均同时适用于StringRedisTemplate。

//注入对象​(RedisTemplate自动关闭Redis连接。)

@Autowired

private RedisTemplate redisTemplate; 

String 


方法



作用


redisTemplate.opsForValue().set("test", "100");

存入数据,不设置过期时间,永久性保存

redisTemplate.setIfAbsent("test", "100");

判断key值是否存在,存在则不存储,不存在则存储


redisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);



存入数据和设置缓存时间


redisTemplate.opsForValue().append("test","Hello");

若key已存在且是一字符串,将该值追加到字符串的末尾。若键不存在,则它被创建并设置为空字符串,因此APPEND在这种特殊情况下将类似于SET。


redisTemplate.opsForValue().get("test")



根据key获取缓存中的val


redisTemplate.opsForValue().size("test"));

返回key所对应的value值的长度


redisTemplate.boundValueOps("test").increment(-1);



val-1



redisTemplate.boundValueOps("test").increment(1);



val +1


List


方法



作用


Long ret = redisTemplate.opsForList().leftPush("list","java");

左插。若键不存在,则先将其创建为空列表

String[] strs = new String[]{"1","2","3"};

Long ret = redisTemplate.opsForList().leftPushAll("list",strs);

批量把一个数组插入到列表中

redisTemplate.opsForList().set("list",1,"setValue");

在列表中index的位置设置value

String leftPop = redisTemplate.opsForList().leftPop("redisList");

从左往右遍历。(该值同时被从列表中删除)

redisTemplate.opsForList().index("listRight",2)

根据下标获取值(下标从0开始)

List<String> range = redisTemplate.opsForList().range("redisList", 0, -1);

查询全部元素

List<String> range1 = redisTemplate.opsForList().range("redisList", 0, 3);

查询前三个元素

Long size = redisTemplate.opsForList().size("redisList");

查询list大小

Set


方法



作用



redisTemplate.opsForSet().add("red_123", "1","2","3");



向指定key中存放set集合



Set<String> resultSet = redisTemplate.opsForSet().members("red_123");



根据key获取set集合



redisTemplate.opsForSet().isMember("red_123", "1")



根据key查看集合中是否存在指定数据


Hash

方法

作用

redisTemplate.opsForHash().put("hash", "hash1", "value1");

往key对应的map中新增(key1,value1)

Map<String, String> map = new HashMap<String, String>();

map.put("map1", "fiala1");

map.put("map2", "fiala2");

redisTemplate.opsForHash().putAll("hash", map);

将Java的HashMap存入redis

Object o = redisTemplate.opsForHash().get("hash", "hash1");

获取key对应的map中hash1的值

Map<Object, Object> hash = redisTemplate.opsForHash().entries("hash");


获取hash对应的map。


Set<Object> hash1 = redisTemplate.opsForHash().keys("hash");

获取hash对应的map中全部子hash集合

List<Object> hash2 = redisTemplate.opsForHash().values("hash");

获取hash对应的map中全部value集合

Boolean aBoolean = redisTemplate.opsForHash().hasKey("hash", "hash1");

判断key对应的map中是否存在键


Cursor<Map.Entry<Object, Object>> curosr = redisTemplate.opsForHash().scan("hash",  ScanOptions.ScanOptions.NONE);

while(curosr.hasNext()){
    Map.Entry<Object, Object> entry = curosr.next();
    System.out.println(entry.getKey()+":"+entry.getValue());
}


使用Cursor在key的hash中迭代,相当于迭代器。

Long delete = redisTemplate.opsForHash().delete("hash", "key1", "key2");

删除key对应的map中多个子hash(可变参数)

其他


方法



作用



redisTemplate.delete("test");



根据key删除缓存



redisTemplate.hasKey("546545");



检查key是否存在,返回boolean值



redisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS);



设置过期时间



redisTemplate.getExpire("test")



根据key获取过期时间。不设的话为-1



redisTemplate.getExpire("test",TimeUnit.SECONDS)



根据key获取过期时间并换算成指定单位


配置

其他网址

​SpringBoot2.0+整合redis,使用 RedisTemplate操作redis - 知乎​

说明

        CacheManage的配置是为了配合注解使用redis而配置的,然而在我的开发使用中不太习惯使用注解,

首先注解确实可以更方便,但是复杂的操作和异常无法处理,这就使的灵活性有所下降,当然一些简单的处理就完全可以配合使用注解了。在下面的测试中,将使用RedisTemplate进行操作 。

配置类

package com.novacloud.information.common.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
@EnableCaching//开启注解
public class RedisConfig {
//如使用注解的话需要配置cacheManager
@Bean
CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
//设置默认超过期时间是1天
defaultCacheConfig.entryTtl(Duration.ofDays(1));
//初始化RedisCacheManager
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
return cacheManager;
}

// 以下两种redisTemplate自由根据场景选择
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);

//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);

ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);

template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
}

操作实例

package com.neopte;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class NeopteApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
public void contextLoads() {
//这里相当于redis对String类型的set操作
redisTemplate.opsForValue().set("test","helloworld");
//这里相当于redis对String类型的get操作
String test = (String)redisTemplate.opsForValue().get("test");
System.out.println(test);
}

}

StringRedisTemplate

基本操作

其他网址

​​

​如何使用StringRedisTemplate操作Redis详​

实例

@RestController
@RequestMapping("/user")
public class UserResource {
private static final Logger log = LoggerFactory.getLogger(UserResource.class);
@Autowired
private UserService userService;

@Autowired
public StringRedisTemplate stringRedisTemplate;

@RequestMapping("/num")
public String countNum() {
String userNum = stringRedisTemplate.opsForValue().get("userNum");
if(StringUtils.isNull(userNum)){
stringRedisTemplate.opsForValue().set("userNum", userService.countNum().toString());
}
return userNum;
}
}

进阶用法

StringRedisTemplate实现事务

stringRedisTemplate.setEnableTransactionSupport(true);
try {
stringRedisTemplate.multi();//开启事务
stringRedisTemplate.opsForValue().increment("count", 1);
stringRedisTemplate.opsForValue().increment("count1", 2);
//提交
stringRedisTemplate.exec();
}catch (Exception e){
log.error(e.getMessage(), e);
//开启回滚
stringRedisTemplate.discard();
}

StringRedisTemplate开启事务之后,不释放连接。如果我们使用Spring事务管理不存在这个问题 

StringRedisTemplate实现乐观锁

redisTemplate.watch("key"); // 1
redisTemplate.multi();
redisTemplate.boundValueOps("key").set(""+id);
List<Object> list= redisTemplate.exec();
System.out.println(list);
if(list != null ){
//操作成功
System.out.println(id+"操作成功");
}else{
//操作失败
System.out.println(id+"操作失败");
}
StringRe

StringRedisTemplate实现分布式锁

String lockKey = "key";
String lockValue = lockKey+System.currentTimeMillis();
// value需要记住用于解锁
while (true){
Boolean ifPresent = stringRedisTemplate.opsForValue().
setIfAbsent("redis-lock:" + lockKey, lockValue, 3, TimeUnit.SECONDS);

if (ifPresent){
log.info("get redis-lock success");
break;
}
}
//解锁
String lockKey = "key";
String lockValue = lockKey + System.currentTimeMillis();
boolean result = false;
// value需要记住用于解锁
stringRedisTemplate.watch("redis-lock:" + lockKey);
String value = stringRedisTemplate.opsForValue().get("redis-lock:" + lockKey);
if (null == value){
result = true;
}else if (value.equals(lockValue)) {
stringRedisTemplate.delete("redis-lock:" + lockKey);
result = true;
}
stringRedisTemplate.unwatch();