缓存只对查询功能有效
创建一个员工表:emp
CREATE TABLE `studymybatis`.`emp` (
`eid` INT NOT NULL AUTO_INCREMENT,
`emp_name` VARCHAR(20),
`age` INT,
`sex` CHAR(1),
`email` VARCHAR(20),
`did` VARCHAR(20),
PRIMARY KEY (`eid`));
INSERT INTO `studymybatis`.`emp` (`emp_name`, `age`, `sex`, `email`, `did`) VALUES ('张三', '21', '男', 'Zhang@163.com', 'D1');
INSERT INTO `studymybatis`.`emp` (`emp_name`, `age`, `sex`, `email`, `did`) VALUES ('李四', '23', '男', 'Lisi@qq.com', 'D2');
INSERT INTO `studymybatis`.`emp` (`emp_name`, `age`, `sex`, `email`, `did`) VALUES ('王二', '22', '男', 'Wang@163.com', 'D2');
INSERT INTO `studymybatis`.`emp` (`emp_name`, `age`, `sex`, `email`, `did`) VALUES ('小红', '20', '女', 'Hong@163.com', 'D1');
INSERT INTO `studymybatis`.`emp` (`emp_name`, `age`, `sex`, `email`, `did`) VALUES ('王梅', '22', '女', 'Mei@qq.com', 'D3');
在pojo包下编写对应的实体类对象Emp
一. 一级缓存
一级缓存默认开启,通过同一个SqlSession即可从缓存中获取数据
一级缓存的范围是:同一个SqlSession
package mapper;
import org.apache.ibatis.annotations.Param;
import pojo.Emp;
public interface EmpMapper {
Emp queryEmpById(@Param("eid") Integer eid);
}
<?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="mapper.EmpMapper"> <!--为mapper接口的全类名-->
<select id="queryEmpById" resultType="Emp">
select * from emp where eid = #{eid}
</select>
</mapper>
import mapper.EmpMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import pojo.Emp;
import utils.SqlSessionUtils;
public class MapperTest {
@Test
public void testQuery(){
SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
EmpMapper mapper1 = sqlSession1.getMapper(EmpMapper.class);
Emp emp1 = mapper1.queryEmpById(1);
System.out.println(emp1);
EmpMapper mapper2 = sqlSession1.getMapper(EmpMapper.class);
Emp emp2 = mapper2.queryEmpById(1); //这一次查询是从缓存中获取的
System.out.println(emp2);
SqlSession sqlSession2 = SqlSessionUtils.getSqlSession();
EmpMapper mapper3 = sqlSession2.getMapper(EmpMapper.class);
Emp emp3 = mapper3.queryEmpById(1); //这一次查询是重新访问数据库获取的
System.out.println(emp3);
}
}
使一级缓存失效的情况:①不同的SqlSession;②同一个SqlSession但是查询条件不同;③同一个SqlSession两次相同查询之间执行了一次增删改操作;④同一个SqlSession两次相同查询之间手动清空了缓存
import mapper.EmpMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import pojo.Emp;
import utils.SqlSessionUtils;
public class MapperTest {
@Test
public void testQuery(){
SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
EmpMapper mapper1 = sqlSession1.getMapper(EmpMapper.class);
Emp emp1 = mapper1.queryEmpById(1);
System.out.println(emp1);
//手动清空缓存
sqlSession1.clearCache();
EmpMapper mapper2 = sqlSession1.getMapper(EmpMapper.class);
Emp emp2 = mapper2.queryEmpById(1); //这一次查询是重新访问数据库获取的
System.out.println(emp2);
}
}
二. 二级缓存
二级缓存需要手动打开,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存
一级缓存的范围是:同一个SqlSessionFactory
二级缓存开启的条件:①查询的数据所转换的实体类类型必须实现序列化的接口;②在映射文件中设置标签<cache/>;③必须在SqlSession关闭或提交以后才有效;
package pojo;
import java.io.Serializable;
public class Emp implements Serializable { //实现序列化接口
//省略
}
package mapper;
import org.apache.ibatis.annotations.Param;
import pojo.Emp;
public interface EmpMapper {
Emp queryEmpById(@Param("eid") Integer eid);
}
<?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="mapper.EmpMapper"> <!--为mapper接口的全类名-->
<cache/> <!--配置缓存标签-->
<select id="queryEmpById" resultType="Emp">
select * from emp where eid = #{eid}
</select>
</mapper>
import mapper.EmpMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import pojo.Emp;
import java.io.IOException;
import java.io.InputStream;
public class MapperTest {
@Test
public void testQuery(){
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
EmpMapper mapper1 = sqlSession1.getMapper(EmpMapper.class);
Emp emp1 = mapper1.queryEmpById(1);
System.out.println(emp1);
//关闭sqlSession1
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
EmpMapper mapper2 = sqlSession2.getMapper(EmpMapper.class);
Emp emp2 = mapper2.queryEmpById(1); //从缓存中获取数据
System.out.println(emp2);
sqlSession2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使二级缓存失效的情况:两次相同查询之间执行了一次增删改操作,一级缓存和二级缓存都会失效
查询顺序:先查询二级缓存再查询一级缓存再查询数据库
三. 第三方缓存EHCache
使用第三方缓存EHCache来实现二级缓存
①在pom.xml中添加依赖
<!-- Mybatis EHCache整合包 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
②创建EHCache的配置文件ehcache.xml(名字必须为ehcache.xml)
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\java\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
③在映射文件中设置标签<cache/>
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>