1.二级缓存
我们知道对于Mybatis的一级缓存,如果两个SqlSession不同,则两个SqlSession查询数据库时,会查询数据库两次。为了解决这个问题Mybatis提供了二级缓存,与一级缓存比较,二级缓存的存储范围更大,多个SqlSession可以共享二级缓存,而且二级缓存可以自己定义要缓存的资源。

SqlSessionFactory层面上的二级缓存默认是不开启的,二级缓存的开席需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置就可以开启缓存了
以上是二级缓存在默认状态下的特征,如果需要调整上述特性,可以通过<cache>元素属性来实现。
Cache标签有六个属性,其中: |属性名|含义| |-|-| |type|指定缓存(cache)接口的实现类型,当需要和ehcache整合时更改该参数值即可。| |flushInterval|刷新间隔。可被设置为任意的正整数,单位毫秒。默认不设置。| |size|引用数目。可被设置为任意正整数,缓存的对象数目等于运行环境的可用内存资源数目。默认是1024。| |readOnly|只读,true或false。只读的缓存会给所有的调用者返回缓存对象的相同实例。默认是false。| |eviction|缓存收回策略。LRU(最近最少使用的),FIFO(先进先出),SOFT( 软引用),WEAK( 弱引用)。默认是 LRU。|
在 Mapper 中,在select中可设置useCache="false"来禁用缓存,默认是开启的;在insert、update、delete中设置flushCache="true"来清空缓存(刷新缓存),默认是会清空缓存。
实例
在上小节案例基础上,测试mybatis二级缓存。
1.改写Users.java 实现串行化接口。
//用户实体类,对应我们users表。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Users implements Serializable {
private Integer uid; //用户编号
private String username; //用户名
private String password; //密码
private String mobile; //手机号码
private String email; //电子邮箱
private String type; //用户类型
}
2.在mybatis-config.xml中开启二级缓存
<settings>
<!--设置启用数据库字段下划线映射到java对象的驼峰式命名属性,默认为false-->
<!-- 配置打印 SQL log 的路径前缀 以及懒加载 -->
<setting name="logPrefix" value="mybatis.sql."/>
<!-- 打开延迟加载的全局开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
3.在usersMapper.xml中开启本名空间下的二级缓存
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.usersMapper">
<!-- 开启本Mapper下的 namespace下的二级缓存 -->
<cache></cache>
<!--查询所有用户-->
<select id="getAllUsers" resultType="Users">
select * from users
</select>
<!--根据用户编号查询某个用户资料-->
<select id="getUser" parameterType="int" resultType="Users" useCache="true">
select * from users where uid=#{uid}
</select>
<!--新增用户-->
<insert id="addUser" parameterType="Users" useGeneratedKeys="true" keyProperty="uid">
insert into users (username,password) values (#{username},#{password})
</insert>
<!--更新用户-->
<update id="updateUser" parameterType="Users">
update users set username = #{username},password=#{password} where uid = #{uid}
</update>
<!--删除用户-->
<delete id="deleteUser" parameterType="int">
delete from users where uid = #{uid}
</delete>
</mapper>
4.编写测试类
@Test
public void testSecnodLevelCache(){
SqlSession session = null;
Users u = null;
try {
session = SqlSessionFactoryUtil.openSqlSession();
u = session.selectOne("getUser", 3);
System.out.println(u);
session.close();
session=null;
//打开一个新的SqlSession
session = SqlSessionFactoryUtil.openSqlSession();
u = session.selectOne("getUser", 3);
System.out.println(u);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (session != null) {
session.close();
}
}
}
运行结果:
15:49:27.884 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - ==> Preparing: select * from users where uid=?
15:49:27.924 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - ==> Parameters: 3(Integer)
15:49:27.974 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - <== Total: 1
Users(uid=3, username=宝宝, password=123456, mobile=15991167345, email=403353606@qq.com, type=admin)
15:49:27.983 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41ab013]
15:49:27.983 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41ab013]
15:49:27.984 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 68857875 to pool.
15:49:27.985 [main] WARN org.apache.ibatis.io.SerialFilterChecker - As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
15:49:27.987 [main] DEBUG com.mapper.usersMapper - Cache Hit Ratio [com.mapper.usersMapper]: 0.5
Users(uid=3, username=宝宝, password=123456, mobile=15991167345, email=403353606@qq.com, type=admin)
我们发现两个不同的SqlSession执行相同的查询语句,仅仅发送了一次select查询语句。说明第二次查询使用了二级缓存。
执行更新语句后会刷新二级缓存。
@Test
public void testSecnodLevelCache(){
SqlSession session = null;
Users u = null;
try {
session = SqlSessionFactoryUtil.openSqlSession();
u = session.selectOne("getUser", 3);
System.out.println(u);
//执行更新操作
u.setPassword("123456");
session.update("updateUser",u);
session.commit();
session.close();
session = SqlSessionFactoryUtil.openSqlSession();
u = session.selectOne("getUser", 3);
System.out.println(u);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (session != null) {
session.close();
}
}
}
运行结果:
15:52:12.552 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - ==> Preparing: select * from users where uid=?
15:52:12.597 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - ==> Parameters: 3(Integer)
15:52:12.647 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - <== Total: 1
Users(uid=3, username=宝宝, password=123456, mobile=15991167345, email=403353606@qq.com, type=admin)
15:52:12.650 [main] DEBUG mybatis.sql.com.mapper.usersMapper.updateUser - ==> Preparing: update users set username = ?,password=? where uid = ?
15:52:12.651 [main] DEBUG mybatis.sql.com.mapper.usersMapper.updateUser - ==> Parameters: 宝宝(String), 123456(String), 3(Integer)
15:52:12.652 [main] DEBUG mybatis.sql.com.mapper.usersMapper.updateUser - <== Updates: 1
15:52:12.652 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41ab013]
15:52:12.653 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41ab013]
15:52:12.653 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41ab013]
15:52:12.653 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 68857875 to pool.
15:52:12.655 [main] WARN org.apache.ibatis.io.SerialFilterChecker - As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
15:52:12.657 [main] DEBUG com.mapper.usersMapper - Cache Hit Ratio [com.mapper.usersMapper]: 0.0
15:52:12.657 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Opening JDBC Connection
15:52:12.657 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Checked out connection 68857875 from pool.
15:52:12.657 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41ab013]
15:52:12.658 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - ==> Preparing: select * from users where uid=?
15:52:12.658 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - ==> Parameters: 3(Integer)
15:52:12.659 [main] DEBUG mybatis.sql.com.mapper.usersMapper.getUser - <== Total: 1
Users(uid=3, username=宝宝, password=123456, mobile=15991167345, email=403353606@qq.com, type=admin)
我们发现执行完更新操作后要刷新二级缓存,所以第二次查询又执行了一次select查询语句。