第二节 String典型场景
一、心法
可以从Redis的String类型的数据结构来考虑其实际业务场景。重点需要记住的是,String类型它是一个变量对应一个值,说白了,就是一对一的场景。这种场景比较多,比如用于缓存当前登陆人的用户信息,缓存某篇文章的访问量。我自己的公司现在是做教育行业的,那么String类型完全可以用于缓存当前学生的身份信息,学生某门课的考试成绩,学生的参与某个活动的次数等等。牢牢记住,Redis的String类型用于"一对一"场景。
二、快速引入Redis
SpringBoot中快速集成Redis的三个步骤。导入依赖,增加配置文件,增加配置代码
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring
redis:
# Redis 数据库索引(默认为 0)
database: 0
# Redis 服务器地址
host: localhost
# Redis 服务器连接端口
port: 6379
password:
timeout: 10s
#数据连接池等配置,可参考其它网上的教程
package com.tyzhou.database;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* @author zhoutianyu
* @date 2020/2/8
* @time 17:11
*/
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
//操作String类型的RedisTemplate
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//指定序列化策略
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
二、String类型的应用
Redis毕竟是一个缓存系统,最最典型的应用就是存放Java实体对象,例如商品对象、用户对象。
毋庸置疑的,我们先把一个对象插入到Redis缓存中,然后再去Redis缓存中取出来。
好,现有一个User对象。注意要在User对象上加入@ToString注解,并实现序列化接口。
package com.tyzhou.redis;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Long id;
private String username;
private String password;
}
Redis操作工具,先写一个非常粗劣的工具类。
@Service
public class StringRedisServiceImpl implements StringRedisService {
private static final Logger LOGGER = LoggerFactory.getLogger(StringRedisServiceImpl.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Boolean exists(String key) {
//todo:key can be null?
return stringRedisTemplate.hasKey(key);
}
@Override
public void set(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
@Override
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
}
核心业务。先把存放到数据库中的User,接着放到Redis缓存里。这样下次查询的时候,就能先从缓存中取。
如果缓存中没有的话,那么就再从数据库中取。通常为了代码的健壮性,需要提供一个判断key是否存在的接口。
我这里主要遇到的坑就是对象与JSON互转。ObjectMapper是FastJson提供的工具类。
先把User对象弄成JSON格式。
把数据以JSON格式存放
String json = objectMapper.writeValueAsString(userFromDB)
stringRedisService.set(userFromDB.getId().toString(),json );
从Redis中读取JSON,要求实体必须提供@ToString注解
String json = stringRedisService.get(userFromDB.getId().toString());
User user = objectMapper.readValue(json, User.class);
import com.fasterxml.jackson.databind.ObjectMapper;
@Service
public class UserItemService ...
@Autowired
private ObjectMapper objectMapper;
public void addUser() throws Exception {
//这里操作数据库成功,返回此User
User userFromDB = insert();
//将其放入缓存
stringRedisService.set(userFromDB.getId().toString(),
objectMapper.writeValueAsString(userFromDB));
}
public User getUser() throws Exception {
User userFromDB = insert();
String key = userFromDB.getId().toString();
//查询的时候,先查询Redis缓存,客户端肯定会传一个ID过来
if (stringRedisService.exists(key)) {
LOGGER.info("从Redis缓存中查询User");
String result = stringRedisService.get(key);
return objectMapper.readValue(result, User.class);
} else {
LOGGER.info("从数据库中查询User");
return userFromDB;
}
}
}
最终效果。
Redis的set与get,实在是太过简单,我想哪个公司都会有。网上的Redis工具类天花乱坠。
估计以后我看到这篇文章的时候,也只会花了不到30秒就扫描完。
JSONObject.parseObject(redisValue, SystemStepDO.class);
redisTemplate.opsForValue().set(key, value);
return redisTemplate.opsForValue().get(key);
redisTemplate.delete(key);