什么是mybatis缓存?
为提升数据库查询效率,MyBatis提供了数据缓存支持,依据数据缓存的有效范围默认定义了一级缓存和二级缓存
演示准备
(1)mapper接口IUserInfoDao.java
package com.jd.userinfo.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.jd.vo.UserInfo;
public interface IUserInfoDao {
List<UserInfo> select();
List<UserInfo> selectByName(@Param("userName")String userName);
boolean delete(@Param("id")int id);
}
(2)MyBatis配置文件user_info.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.jd.userinfo.dao.IUserInfoDao">
<select id="selectByName" resultType="com.jd.vo.UserInfo">
select * from user_inf
<where>
user_name like #{userName}
</where>
</select>
<select id="select" resultType="com.jd.vo.UserInfo">
select * from user_inf
</select>
<delete id="delete" flushCache="false">
delete from user_inf where id = #{id}
</delete>
</mapper>
(3)MyBatis配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置下划线命名自动转驼峰法命 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<environments default="development">
<!-- 配置数据库连接信息 -->
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 注册Mapper xml文件 -->
<mappers>
<mapper resource="./user_info.xml" />
</mappers>
</configuration>
一级缓存
(1)该缓存默认开启,不能关闭
(2)该缓存为sqlSession级别缓存(又称本地缓存):即同一个sqlSession内,两次紧邻的select查询中,第一次从数据库获取查询的数据并将获取到的数据库信息作为缓存存放到本地;第二次查询时则会在本地缓存中查询。
(3)某些情况会使缓存失效
1、在不同sqlSession中查询
public class Test {
public static void main(String[] args) {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
//第一次查询
List<UserInfo> list = userInfoDao.select();
System.out.println(list.size());
sqlSession.close();
//第二次不同sqlSession查询
sqlSession = sqlSessionFactory.openSession();
userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
list = userInfoDao.select();
System.out.println(list.size());
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
2、相同SqlSession中查询数据,但查询条件不同
public class Test {
public static void main(String[] args) {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
List<UserInfo> list = userInfoDao.selectByName("%admin%");
System.out.println(list.size());
list = userInfoDao.selectByName("%walylz%");
System.out.println(list.size());
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
3、相同SqlSession中查询数据,但两次查询之间执行了增删改操作
public class Test {
public static void main(String[] args) {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
//第一次查询
List<UserInfo> list = userInfoDao.select();
System.out.println(list.size());
//删除
System.out.println(userInfoDao.delete(1));
//第二次查询
list = userInfoDao.select();
System.out.println(list.size());
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
4、相同SqlSession中查询数据,但第二次查询前,程序调用SqlSession对象clearCache()方法手动清除了一级缓存
public class Test {
public static void main(String[] args) {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
//第一次查询
List<UserInfo> list = userInfoDao.select();
System.out.println(list.size());
//手动清除缓存
sqlSession.clearCache();
//第二次查询
list = userInfoDao.select();
System.out.println(list.size());
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
二级缓存
(1)该缓存默认关闭,使用二级缓存需要在每个XML映射文件中添加<cache></cache>以配置该级缓存。二级缓存可以通过在全局配置文件配置setting标签来关闭该级缓存
(2)该级缓存为namespace级别的缓存
(3)工作机制:通过SqlSession查询数据,这些数据将会放到当前会话的一级缓存中;如果当前会话关闭,则一级缓存中的数据会被保存到二级缓存中,此后新的SqlSession将从二级缓存中查找数据
第一步:在xml映射中添加cache标签开启二级缓存
<?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.jd.userinfo.dao.IUserInfoDao">
<!-- cache标签用于开启二级缓存 -->
<cache></cache>
<select id="selectByName" resultType="com.jd.vo.UserInfo">
select * from user_inf
<where>
user_name like #{userName}
</where>
</select>
<select id="select" resultType="com.jd.vo.UserInfo">
select * from user_inf
</select>
<delete id="delete" flushCache="false">
delete from user_inf where id = #{id}
</delete>
</mapper>
第二步:测试
public class Test {
public static void main(String[] args) {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
//第一次查询
List<UserInfo> list = userInfoDao.select();
System.out.println(list.size());
//第二次查询
list = userInfoDao.select();
System.out.println(list.size());
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
(4)select标签的useCache属性用于设置是否使用二级缓存;insert、update、delete或select标签均有flushCache属性,其中增删改默认true,即sql执行以后,会同时清空一级和二级缓存,查询默认false
如:
(5)为了提高扩展性,MyBatis定义了Cache缓存接口,可以通过实现该缓存接口自定义二级缓存,jar包下载:https://github.com/mybatis
附:log4j配置
log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>