1 概述
本文演示了如何在Spring Boot
中将Redis
作为缓存应用,具体的内容包含:
- 环境搭建
- 我的项目搭建
- 测试
2 环境
Redis
MySQL
MyBatis Plus
3 Redis
装置
Redis
装置非常简单,以笔者的Manjaro
为例,间接paru
装置:
paru -S redis
Ubuntu
、CentOS
之类的都提供了软件包装置:
sudo apt install redissudo yum install redis
如果想从源码编译装置:
wget http://download.redis.io/redis-stable.tar.gztar xvzf redis-stable.tar.gzcd redis-stablemake
Windows
以及其余零碎的装置能够参考此处。
4 新建我的项目
新建我的项目,退出如下依赖:
Maven
:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional></dependency><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version></dependency>
Gradle
:
implementation("com.baomidou:mybatis-plus-boot-starter:3.4.2")implementation("mysql:mysql-connector-java:8.0.23")
我的项目构造:
5 配置类
MyBatis Plus
+Redis
配置类:
@Configuration@MapperScan("com.example.demo.dao")public class MyBatisPlusConfig {}
@Configuration@AutoConfigureAfter(RedisAutoConfiguration.class)@EnableCachingpublic class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setConnectionFactory(factory); return template; } @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith( RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()) ).serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()) ); return RedisCacheManager.builder(factory).cacheDefaults(configuration).build(); }}
重点说一下Redis
配置类,这个类次要生成两个Bean
:
RedisTemplate
:简化Redis
操作的数据拜访类CacheManager
:Spring
的地方缓存管理器
其中RedisTemplate
是一个模板类,第一个参数的类型是该template
应用的键的类型,通常是String
,第二个参数的类型是该template
应用的值的类型,通常为Object
或Seriazable
。
setKeySerializer
和setValueSerializer
别离设置键值的序列化器。键个别为String
类型,能够应用自带的StringRedisSerializer
。对于值,能够应用自带的GenericJackson2RedisSerializer
。
CacheManager
的配置相似,就不从新说了。
6 实体类
@Getter@Setter@ToString@AllArgsConstructor@NoArgsConstructorpublic class User { private Integer id; private String name;}
7 长久层
public interface UserMapper extends BaseMapper<User> {}
8 业务层
@org.springframework.stereotype.Service@Transactional@RequiredArgsConstructor(onConstructor = @__(@Autowired))public class Service { private final UserMapper mapper; @CachePut(value = "user",key = "#user.id") public User save(User user){ User oldUser = mapper.selectById(user.getId()); if(oldUser == null){ mapper.insert(user); return user; } if(mapper.updateById(user) == 1) return user; return oldUser; } @CacheEvict(value = "user",key = "#id") public boolean delete(Integer id){ return mapper.deleteById(id) == 1; } @Cacheable(value = "user",key = "#id") public User select(Integer id){ return mapper.selectById(id); } @Cacheable(value="allUser",key = "#root.target+#root.methodName") //root.target是指标类,这里是com.example.demo.Service,root.methodName是办法名,这里是selectAll public List<User> selectAll(){ return mapper.selectList(null); }}
注解阐明如下:
@CachePut
:执行办法体再将返回值缓存,个别用于更新数据@CacheEvict
:删除缓存,个别用于删除数据@Cacheable
:查问缓存,如果有缓存就间接返回,没有缓存的话执行办法体并将返回值存入缓存,个别用于查问数据
三个注解都波及到了key
以及value
属性,实际上,真正的存入Redis
的key
是两者的组合,比方:
@Cacheable(value="user",key="#id")
则存入的Redis
中的key
为:
而存入对应的值为办法返回值序列化后的后果,比方如果返回值为User
,则会被序列化为:
9 配置文件
spring: datasource: url: jdbc:mysql://localhost:3306/test username: root password: 123456 redis: database: 0 host: 127.0.0.1 port: 6379logging: level: com.example.demo: debug
spring.redis.database
指定数据库的索引,默认为0,host
与port
别离指定主机(默认本地)以及端口(默认6379
)。
也就是说,简略配置的话能够齐全省略Redis
相干配置,仅指定数据库连贯url
、用户名以及明码:
spring: datasource: url: jdbc:mysql://localhost:3306/test username: root password: 123456logging: level: com.example.demo: debug
10 启动Redis
10.1 启动Redis
服务器
Redis
服务器启动须要一个配置文件,默认地位为/etc/redis.conf
(源码编译装置的话在源文件夹内),倡议先复制一份:
cp /etc/redis.conf ~/Desktop/
默认的配置文件为单机Redis
配置,端口6379
,redis-server
能够间接运行:
sudo redis-server redis.conf
10.2 连贯服务器
连贯能够通过自带的redis-cli
命令:
redis-cli -h localhost -p 6379
默认状况下能够间接应用
redis-cli
连贯。
基本操作:
keys *
:查问所有键get key
:查问key
所对应的值flushall
:清空所有键
11 测试
@SpringBootTest@RequiredArgsConstructor(onConstructor = @__(@Autowired))class DemoApplicationTests { private final Service service; @Test void select() { service.select(1); service.select(1); } @Test void selectAll(){ service.selectAll(); service.selectAll(); } @Test void delete(){ service.delete(1); } @Test void save(){ User user = new User(1,"name1"); service.save(user); service.select(user.getId()); user.setName("name2"); service.save(user); service.select(user.getId()); }}
执行其中的select
,会发现MyBatis Plus
只有一次select
的输入,证实缓存失效了:
而把缓存注解去掉后,会有两次select
输入:
其它测试方法就不截图了,原理相似。
12 附录:Kotlin
中的一些细节
12.1 String
数组
其实@Cacheable
/@CacheEvict
/@CachePut
中的value
都是String []
,在Java
中能够间接写上value
,在Kotlin
中须要[value]
。
12.2 @class
序列化到Redis
时,实体类会被加上一个@class
字段:
这个标识供Jackson
反序列化时应用,笔者一开始的实体类实现是:
data class User(var id:Int?=null, var name:String="")
然而序列化后不携带@class
字段:
在反序列化时间接报错:
Could not read JSON: Missing type id when trying to resolve subtype of [simple type, class java.lang.Object]: missing type id property '@class' at [Source: (byte[])"{"id":1,"name":"name2"}"; line: 1, column: 23]; nested exception is com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class java.lang.Object]: missing type id property '@class' at [Source: (byte[])"{"id":1,"name":"name2"}"; line: 1, column: 23]
解决办法有两个:
- 手动增加
@class
字段 - 将实体类设为
open
12.2.1 手动增加@class
精确来说并不是手动增加,而是让注解增加,须要增加一个类注解@JsonTypeInfo
:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)data class User(var id:Int?=null, var name:String="")
该注解的use
用于指定类型标识码,该值只能为JsonTypeInfo.Id.CLASS
。
12.2.2 将实体类设置为open
在Java
中,实体类没有任何额定配置,Redis
序列化/反序列化一样没有问题,是因为值序列化器GenericJackson2JsonRedisSerializer
,该类会主动增加一个@class
字段,因而不会呈现下面的问题。
然而在Kotlin
中,类默认不是open
的,也就是无奈增加@class
字段,因而便会反序列化失败,解决方案是将实体类设置为open
:
open class User(var id:Int?=null, var name:String="")
然而毛病是不能应用data class
了。
13 参考源码
Java
版:
- Github
- 码云
- CODECHINA
Kotlin
版:
- Github
- 码云
- CODECHINA