redis.clients
jedis
3.7.0
org.junit.jupiter
junit-jupiter
5.7.0
test
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static {
//配置连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
//最大连接数,也就是线程池最多可以创建8个连接
poolConfig.setMaxTotal(8);
//最大空闲连接
poolConfig.setMaxIdle(8);
//最小空闲连接,超过一段时间后,如果一直没有人访问,空闲连接就会被释放,直到为0为止
poolConfig.setMinIdle(0);
//最大等待时间,如果超过1000毫秒,则报错
poolConfig.setMaxWaitMillis(1000);
//创建连接池对象
jedisPool = new JedisPool(poolConfig,
"127.0.0.1",6379,1000,"123456");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
public class JedisTest {
private Jedis jedis;
@BeforeEach
void setUp(){
//建立连接
jedis = JedisConnectionFactory.getJedis();
//选择库
jedis.select(0);
}
@Test
void testString() {
//存入数据
String result = jedis.set("name", "Jack");
System.out.println("result = " + result);
// 获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
}
@AfterEach
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
}
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis。
提供了对不同Redis客户端的整合(Lettuce和Jedis)
提供了RedisTemplate统一API来操作Redis
支持Redis的发布订阅模型
支持Redis哨兵和Redis集群
支持基于Lettuce的响应式编程
支持基于JDK.JSON.字符串.Spring对象的数据序列化及反序列化
支持基于Redis的JDKCollection实现
org.apache.commons
commons-pool2
com.fasterxml.jackson.core
jackson-databind
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
lettuce:
pool:
max-active: 8 #最大连接
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
max-wait: 100ms #连接等待时间
@SpringBootTest
class SpringdataredisDemoApplicationTests {
@Resource
private RedisTemplate redisTemplate;
@Test
void testString() {
redisTemplate.opsForValue().set("name","Tom");
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name); //Tom
}
}
我们这时可能会发现一个问题,那就是我可以在Java代码中set和get,取值都没问题。但我如果在代码中set,在命令端get,就会出现一堆看不懂的二进制,如下:
原因:RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,key也会被序列化为字节形式,默认是采用JDK序列化。
因为这种序列化方式一是我们读不懂,二是内存占用较大。
所以我们要修改序列化方式,采用自定义的方式。
@Configuration
public class RedisConfig {
@Bean
@Resource
public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory){
// 创建RedisTemplate对象
RedisTemplate template = new RedisTemplate<>();
// 设置连接工厂
template.setConnectionFactory(connectionFactory);
// 创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer =
new GenericJackson2JsonRedisSerializer();
// 设置Key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// 设置Value的序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
// 返回
return template;
}
}
我们发现不管是key还是value,都已经被我们自定义序列化。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private Integer age;
}
@Test
void testSaveUser(){
redisTemplate.opsForValue().set("user:1",new User("Uzi",21));
User user = (User) redisTemplate.opsForValue().get("user:1");
System.out.println(user);
}
注意:尽管JSON序列化可以满足我们的需求,但仍然存在一些问题,如上图,除了我们set的数据以外,还有个@class,这是一笔不小的内存开销啊,那么有方法可以解决吗?
解决办法:使用StringRedisTemplate
为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
@SpringBootTest
public class RedisStringTests {
@Resource
private StringRedisTemplate stringRedisTemplate;
//用来手动序列化和反序列化,需引入Jackson包
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testString() {
stringRedisTemplate.opsForValue().set("name","Tom");
Object name = stringRedisTemplate.opsForValue().get("name");
System.out.println(name);
}
@Test
void testSaveUser() throws JsonProcessingException {
User user = new User("Uzi",21);
//手动序列化
String json = mapper.writeValueAsString(user);
stringRedisTemplate.opsForValue().set("user:1",json);
String jsonUser = stringRedisTemplate.opsForValue().get("user:1");
//手动反序列化
User user1 = mapper.readValue(jsonUser, User.class);
System.out.println(user1);
}
}