MyBatis Plus+Spring Boot 实现一二级缓存以及自定义缓存
# 一级缓存
首先需要在 application.yml 中进行配置
mybatis-plus:
# 指定具体xml路径 全路径
mapper-locations: classpath*:/com/fengqianrun/mybatisplus/**/*Mapper.xml
# 设置实体路径位置
type-aliases-package: com.fengqianrun.mybatisplus.bean
configuration:
# 开启一级缓存,默认是开启的
local-cache-scope: SESSION
GlobalConfig:
# 关闭 banner 效果
banner: false
2
3
4
5
6
7
8
9
10
11
其次在查询方法上使用注解 @Transactional,@Transactional 代表就像一个 session,我们在这里面重复执行查询,就只会查询一次
@Transactional
@GetMapping("/testOne")
public UserBean testOne(){
UserBean userBean = cacheOneMapper.testOne();
userBean = null;
userBean = cacheOneMapper.testOne();
return userBean;
}
2
3
4
5
6
7
8
# 二级缓存
首先,在 application.yml 配置文件中添加如下配置:
mybatis-plus:
configuration:
# 开启二级缓存
cache-enabled: true
2
3
4
必须实现要给对象进行 Serializable,例如:
@Data
@TableName("user")
public class UserBean implements Serializable {
// ...
}
2
3
4
5
最后,需要在 Mapper 接口中使用 @CacheNamespace ,使用该注解可以方便地为每个 Mapper 接口定义独立的缓存空间,并指定不同的缓存实现和缓存策略,从而更好地控制缓存效果。
@Mapper
@CacheNamespace(eviction = FifoCache.class)
public interface CacheTwoMapper extends BaseMapper<UserBean> {
List<UserBean> testAll();
UserBean testOne();
}
2
3
4
5
6
但如果 Mapper 接口有对应的 XML,则需要在 XML 描述 cache,使用注解 @CacheNamespace 就会失效,两个一起存在就会报错
<mapper namespace="com.fengqianrun.mybatisplus.cache2.CacheTwoMapper">
<cache eviction="fifo"/>
<select id="testAll" resultType="com.fengqianrun.mybatisplus.bean.UserBean">
select * from user
</select>
<select id="testOne" resultType="com.fengqianrun.mybatisplus.bean.UserBean">
select * from user where id = 1
</select>
</mapper>
2
3
4
5
6
7
8
9
二级缓存默认情况下是使用 MyBatis
自带的 PerpetualCache
实现,可以通过配置文件中的属性来设置缓存实现类和其他参数。另外,在使用二级缓存时,
需要注意避免数据并发更新导致脏数据的问题,可以通过设置缓存刷新时间等方式来解决这个问题。
# 自定义缓存
如果你是但应用程序的话,使用以上的配置方式没有问题,但如果你是分布式或微服务,那么就会造成数据不一致的问题,此时我们需要借助其他缓存,比如 Redis 来缓存我们的查询数据。自定义缓存也只是在二级缓存基础上的改造,所以规则和二级缓存一样。
实现 org.apache.ibatis.cache.Cache
类
public class MyCache implements Cache {
/**
* id 会是 mapper 接口的名称
*/
private final String id;
/**
* 可以替换为 Redis
*/
private Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>();
public MyCache(String id) {
this.id = id;
}
/**
* 缓存唯一标识
* @return
*/
@Override
public String getId() {
return id;
}
/**
* 将键值对放入缓存中
* @param key
* @param value
*/
@Override
public void putObject(Object key, Object value) {
System.out.println("添加-自定义缓存: "+key+" "+value);
cache.put(key, value);
}
/**
* 从缓存中获取指定键的值
* @param key
*/
@Override
public Object getObject(Object key) {
System.out.println("查询-自定义缓存: "+key);
return cache.get(key);
}
/**
* 从缓存中移除指定键的值
* @param key
*/
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
/**
* 清空缓存
*/
@Override
public void clear() {
cache.clear();
}
/**
* 获取缓存中键值对的数量
* @return
*/
@Override
public int getSize() {
return cache.size();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
具体的 mapper
@Mapper
@CacheNamespace(implementation = MyCache.class,eviction = FifoCache.class)
public interface CacheThreeMapper extends BaseMapper<UserBean> {
@Select("select * from user")
List<UserBean> testAll();
@Select("select * from user where id = 1")
UserBean testOne();
}
2
3
4
5
6
7
8
9
10
我们还可以在 mapper 接口上加 @CacheNamespaceRef 注解,当我们在一个 Mapper 接口中需要使用其他 Mapper 接口所定义的缓存时,可以通过 @CacheNamespaceRef 注解来实现。该注解用于指定另一个 Mapper 接口的 Class 对象,表示当前 Mapper 接口需要引用该接口所定义的缓存命名空间。@CacheNamespaceRef (XXXXXMapper.class)