环境信息
- JDK 版本信息
1.8
- SpringBoot 版本、依赖信息
org.springframework.boot
spring-boot-starter-parent
2.0.2.RELEASE
我们在 SpringBoot 中使用 Redis 时,会引入如下的 redis starter
org.springframework.boot
spring-boot-starter-data-redis
这个 starter 引入了 jedis 和 spring-data-redis 两个与 redis 核心的包。
一些核心类的定义
- RedisConnection
RedisConnection 处理了与 redis 后端的通信。它提供了底层的方法,可以与redis通信,这些方法的输入和返回都是二进制的值,即 byte[](字节数组)。 如果需要直接使用 RedisConnection,则需要在调用方法时,自己处理序列化和反序列化的问题。
- RedisTemplate
与 RedisConnection 相比,RedisTemplate 提供了较为抽象的方法。我们在使用 RedisTemplate 时,通常需要自己去指定 key 和 value 的序列化器。如果没有指定,则使用默认的 JdkSerializationRedisSerializer(JDK 的序列化策略),可以查看其源码如下:
public class RedisTemplate extends RedisAccessor implements RedisOperations, BeanClassLoaderAware {
...
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;
private RedisSerializer stringSerializer = new StringRedisSerializer();
...
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
...
initialized = true;
}
- StringRedisTemplate
最常用的 redis 客户端,用于存取 key 和 value 都是字符串类型的数据。默认采用 String 的序列化策略(StringRedisSerializer),可以查看其源码如下:
public class StringRedisTemplate extends RedisTemplate {
/**
* Constructs a new StringRedisTemplate
instance. {@link #setConnectionFactory(RedisConnectionFactory)}
* and {@link #afterPropertiesSet()} still need to be called.
*/
public StringRedisTemplate() {
RedisSerializer stringSerializer = new StringRedisSerializer();
setKeySerializer(stringSerializer);
setValueSerializer(stringSerializer);
setHashKeySerializer(stringSerializer);
setHashValueSerializer(stringSerializer);
}
...
}
RedisConnection、RedisTemplate 和 StringRedisTemplate 的使用实例
- Java Object(CityInfo)定义
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 城市信息
* Created by Qinyi.
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CityInfo implements Serializable {
/** 城市 */
private String city;
/** 经度 */
private Double longitude;
/** 纬度 */
private Double latitude;
}
- Redis 的配置类:RedisConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis 配置
* Created by Qinyi.
*/
@Configuration
public class RedisConfig {
private final RedisConnectionFactory redisConnectionFactory;
@Autowired
public RedisConfig(RedisConnectionFactory redisConnectionFactory) {
this.redisConnectionFactory = redisConnectionFactory;
}
/**
* 实例化 RedisConnection
* SpringBoot 会自动实例化 RedisConnectionFactory, 但是不会自动实例化 RedisConnection
* */
@Bean("RedisConnection")
RedisConnection getConn(){
return redisConnectionFactory.getConnection();
}
/**
* 配置 RedisTemplate key/value 的序列化方式
* */
@Bean("RedisTemplate")
RedisTemplate getRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();
// RedisTemplate key/value 默认的序列化策略
JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer();
// StringRedisTemplate key/value 默认的序列化策略
RedisSerializer stringSerializer = new StringRedisSerializer();
template.setConnectionFactory(factory);
template.setKeySerializer(stringSerializer);
template.setValueSerializer(redisSerializer);
return template;
}
}
- 测试用例:RedisOpTest
import com.alibaba.fastjson.JSON;
import com.imooc.ad.Application;
import com.imooc.ad.vo.CityInfo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;
import java.nio.charset.StandardCharsets;
/**
* Redis 操作测试用例
* Created by Qinyi.
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class},
webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class RedisOpTest {
/** 注入 RedisConnection (RedisConfig 中配置)*/
@Autowired
@Qualifier("RedisConnection")
private RedisConnection connection;
/** 注入 RedisTemplate (RedisConfig 中配置), 自定义了 key 和 value 的序列化器 */
@Autowired
@Qualifier("RedisTemplate")
private RedisTemplate redisTemplate;
/** 注入 StringRedisTemplate, 使用默认配置 */
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void testUseRedisConnection() {
String key = "RedisConnection";
// -----------------------------------使用 RedisConnection 存取 String 对象---------------------------------------
String value = "qinyi";
connection.set(key.getBytes(StandardCharsets.UTF_8), value.getBytes(StandardCharsets.UTF_8));
byte[] ret = connection.get(key.getBytes(StandardCharsets.UTF_8));
assert ret != null;
System.out.println(new String(ret));
connection.flushAll(); // 慎用
// -----------------------------------使用 RedisConnection 存取 Java 对象-----------------------------------------
CityInfo cityInfo = CityInfo.builder()
.city("suzhou").longitude(116.58).latitude(33.38).build();
JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
connection.set(key.getBytes(StandardCharsets.UTF_8), serializer.serialize(cityInfo));
System.out.println(serializer.deserialize(connection.get(key.getBytes(StandardCharsets.UTF_8))));
connection.flushAll(); // 慎用
}
@Test
public void testUseRedisTemplate() {
String key = "RedisTemplate";
// -----------------------------------使用 RedisTemplate 存取 Java 对象-------------------------------------------
CityInfo cityInfo = CityInfo.builder()
.city("suzhou").longitude(116.58).latitude(33.38).build();
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, cityInfo);
System.out.println(valueOperations.get(key));
connection.flushAll(); // 慎用
}
@Test
public void testUseStringRedisTemplate() {
String key = "StringRedisTemplate";
// -----------------------------------使用 StringRedisTemplate 存取 String 对象-----------------------------------
CityInfo cityInfo = CityInfo.builder()
.city("suzhou").longitude(116.58).latitude(33.38).build();
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(key, JSON.toJSONString(cityInfo));
System.out.println(JSON.parseObject(valueOperations.get(key), CityInfo.class));
connection.flushAll(); // 慎用
}
}
总结
- 当需要存取的数据是字符串类型时(大多数情况下),使用 StringRedisTemplate
- 当需要存取的数据是 Java Object 时,使用 RedisTemplate(需要定义好序列化策略)
- 不需要使用 RedisConnection
-
欢迎刚入门的Java小白朋友们加入Java学习之家9un:985331340
里面提供免费的Java的学习资料(里面有企业级技术、日常练习案例等多个知识点的资料,每晚我还会在群内直播上课)