【MyBatis】MyBatis基础教程(9)
前言:
本文内容:缓存简介、一级缓存、二级缓存
推荐免费MyBatis基础教程视频:【狂神说Java】Mybatis最新完整教程IDEA版通俗易懂_哔哩哔哩_bilibili
缓存简介
查询 连接数据库 耗费资源
缓存就是将查询的数据放入缓存中,减轻服务器的消耗
缓存
什么是缓存
- 存在内存中的临时数据
- 用户经常查询的数据放在缓存中,提高查询效率,解决高并发问题
为什么使用缓存
- 减少和数据的交互次数,减少系统开销,提高效率
什么样的数据能使用缓存
- 经常查询并且不经常改变的数据
MyBatis缓存
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
MyBatis系统默认定义一级缓存和二级缓存
默认情况下,只启用了本地的会话缓存(一级缓存),它仅仅对一个会话中的数据进行缓存。
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
1 | <cache/> |
一级缓存
创建一个新的Maven模块,复制上一个模块的代码,使用User表创建实体类,修改核心配置文件
注意:一级缓存默认开启且无法关闭
测试一级缓存
-
开启日志
-
编写所需要要接口和xml配置文件
UserMapper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package com.jokerdig.mapper;
import com.jokerdig.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author Joker大雄
* @data 2022/5/5 - 12:12
**/
public interface UserMapper {
// 查询用户
User getUser(int id);
}UserMapper.xml
1
2
3
4
5
6
7
8
9
10
11
<mapper namespace="com.jokerdig.mapper.UserMapper">
<!-- 查询用户 来测试缓存-->
<select id="getUser" resultType="user">
select * from user where id =#{id}
</select>
</mapper> -
测试运行
UserTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package com.jokerdig.test;
import com.jokerdig.mapper.UserMapper;
import com.jokerdig.pojo.User;
import com.jokerdig.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
/**
* @author Joker大雄
* @data 2022/5/5 - 12:08
**/
public class UserTest {
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUser(1);
System.out.println(user);
// 在查一遍同样的用户
System.out.println("============================");
User user1 = mapper.getUser(1);
System.out.println(user1);
sqlSession.close();
}
}运行结果,观察查询语句执行了几次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15......
Opening JDBC Connection
Created connection 1019384604.
==> Preparing: select * from user where id =?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, admin, 123
<== Total: 1
User(id=1, name=admin, pwd=123)
============================
User(id=1, name=admin, pwd=123)
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3cc2931c]
Returned connection 1019384604 to pool.
Process finished with exit code 0
缓存注意事项
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用LRU算法来清除不需要的缓存。
- 缓存不会定时进行刷新。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
- 缓存可使用
clearCache()
手动清除
二级缓存
启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
1 | <cache/> |
使用@CacheNamespaceRef 注解指定缓存作用域。
二级缓存工作机制
- 一个会话查询一条数据,数据就被放在一级缓存中,会话关闭(一级缓存)即失效
- 我们需要的会话关闭了,一级缓存中的数据被保存到二级缓存中(一级缓存失效后,数据被保存到二级缓存)
- 不同mapper查出的数据会放在自己对应的缓存中
- 二级缓存基于namespace,一个命名空间对应一个二级缓存
这些属性可以通过 cache 元素的属性来修改。比如:
1 | <cache |
缓存清除策略
LRU
– 最近最少使用:移除最长时间不被使用的对象。(默认)FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
测试二级缓存
-
开启全局缓存
mybatis-config.xml
1
2<!-- 开启全局缓存 默认是开启的 这里只是为了更好识别-->
<setting name="cacheEnabled" value="true"/> -
在xml中开启缓存
1
2<!--开启二级缓存-->
<cache/>也可以添加一些配置
1
2
3
4
5<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/> -
测试运行
UserTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void test1(){
// 创建两个不同的sqlsession 来测试
SqlSession sqlSession = MyBatisUtil.getSqlSession();
SqlSession sqlSession1 = MyBatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User user = mapper.getUser(1);
System.out.println(user);
// 关闭第一个sqlsession 一级缓存关闭 数据被放到二级缓存
sqlSession.close();
// 在查一遍同样的用户
System.out.println("============================");
User user1 = mapper1.getUser(1);
System.out.println(user1);
sqlSession1.close();
}运行结果,发现二级缓存在第一个sqlSession关闭后有效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Opening JDBC Connection
Created connection 1183888521.
==> Preparing: select * from user where id =?
==> Parameters: 1(Integer)
<== Columns: id, name, pwd
<== Row: 1, admin, 123
<== Total: 1
User(id=1, name=admin, pwd=123)
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4690b489]
Returned connection 1183888521 to pool.
============================
Cache Hit Ratio [com.jokerdig.mapper.UserMapper]: 0.5
User(id=1, name=admin, pwd=123)
Process finished with exit code 0
我们在创建实体类时,最好为其实现序列化
Serializable
小结
- 只要开启了二级缓存,在同一个Mapper下有效
- 所有的数据都会先放在一级缓存中
- 只有当会话提交,或者关闭的时候,才会提交二级缓存
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hey,Joker!
评论
ValineTwikoo