MyBatis系统默认定义了两级缓存,分别是一级缓存和二级缓存。
@Test
public void test01() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee emp1 = mapper.getEmpById(2);
System.out.println(emp1);
Employee emp2 = mapper.getEmpById(2);
System.out.println(emp2);
System.out.println(emp1 == emp2);
}finally {
sqlSession.close();
}
}
DEBUG 04-07 20:46:55,077 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 20:46:55,094 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 20:46:55,110 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
true
可以看到,进行两次查询,只发送了一次sql,并且两次查询的对象是同一个。即与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
@Test
public void test02() throws IOException {
SqlSession sqlSession1 = getSqlSessionFactory().openSession();
SqlSession sqlSession2 = getSqlSessionFactory().openSession();
try {
EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
Employee emp1 = mapper1.getEmpById(2);
System.out.println(emp1);
sqlSession1.close(); // 会话关闭
Employee emp2 = mapper2.getEmpById(2);
System.out.println(emp2);
sqlSession2.close();
}finally {
}
}
DEBUG 04-07 20:55:45,406 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 20:55:45,425 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 20:55:45,438 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-07 20:55:45,451 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 20:55:45,451 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 20:55:45,452 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
@Test
public void test01() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee emp1 = mapper.getEmpById(2);
System.out.println(emp1);
Employee emp2 = mapper.getEmpById(4);
System.out.println(emp2);
System.out.println(emp1 == emp2);
}finally {
sqlSession.close();
}
}
DEBUG 04-07 20:57:47,064 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 20:57:47,078 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 20:57:47,092 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-07 20:57:47,093 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 20:57:47,093 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 20:57:47,094 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=4, lastName='alan', gender='1', email='jerry@qq.com', dept=null}
false
分别查询2号和4号employee,发送了两次sql,因为第二次查询时当前一级缓存还没有4号employee数据
@Test
public void test03() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee emp1 = mapper.getEmpById(2);
System.out.println(emp1);
// 添加一条记录
mapper.addEmp(new Employee(3,"ray", "1", "[email protected]", null));
Employee emp2 = mapper.getEmpById(2);
System.out.println(emp2);
System.out.println(emp1 == emp2);
}finally {
sqlSession.close();
}
}
DEBUG 04-07 21:36:14,924 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,937 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,951 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-07 21:36:14,951 ==> Preparing: insert into tbl_employee(last_name, gender, email) values(?, ?, ?) (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,951 ==> Parameters: ray(String), 1(String), ray@qq.com(String) (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,952 <== Updates: 1 (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,953 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,953 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 21:36:14,953 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
false
在查询ID为2和4的employee之间,插入了一条ID为3的记录,导致缓存失效,原因在于这次添加可能会对当前数据有影响(删改类似)
@Test
public void test04() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee emp1 = mapper.getEmpById(2);
System.out.println(emp1);
sqlSession.clearCache();
Employee emp2 = mapper.getEmpById(2);
System.out.println(emp2);
System.out.println(emp1 == emp2);
}finally {
sqlSession.close();
}
}
DEBUG 04-07 21:42:38,146 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 21:42:38,162 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 21:42:38,176 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-07 21:42:38,176 ==> Preparing: select * from tbl_employee where id=? (BaseJdbcLogger.java:137)
DEBUG 04-07 21:42:38,176 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-07 21:42:38,177 <== Total: 1 (BaseJdbcLogger.java:137)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
false
一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中
如果会话关闭,一级缓存的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容
不同的namespace查出的数据会放在自己对应的缓存中
总结:查出的数据都会默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
<setting name="cacheEnabled" value="true"/>`
<cache type="org.mybatis.caches.ehcache.EhcacheCache">cache>
public class Employee implements Serializable {
private Integer id;
private String lastName;
private String gender;
private String email;
private Department dept;
}
中设置cacheEnabled=true / false 开启/关闭缓存(注意:二级缓存,一级缓存一直可用)
标签都有useCache=true /false 使用/不使用缓存(注意:false表示一级缓存依然使用,二级缓存不使用)。<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" useCache="true">
select * from tbl_employee where id = #{id}
select>
@Test
public void testSecondLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession1 = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpById(2);
System.out.println(emp);
sqlSession.close();
Employee emp1 = mapper1.getEmpById(2);
System.out.println(emp1);
sqlSession.close();
System.out.println(emp == emp1);
}finally {
}
}
DEBUG 04-08 20:31:54,848 Initialised cache: com.atguigu.mybatis.dao.EmployeeMapper (Cache.java:1165)
DEBUG 04-08 20:31:54,849 CacheDecoratorFactory not configured for defaultCache. Skipping for 'com.atguigu.mybatis.dao.EmployeeMapper'. (ConfigurationHelper.java:354)
DEBUG 04-08 20:31:54,861 Cache Hit Ratio [com.atguigu.mybatis.dao.EmployeeMapper]: 0.0 (LoggingCache.java:62)
DEBUG 04-08 20:31:54,993 ==> Preparing: select * from tbl_employee where id = ? (BaseJdbcLogger.java:145)
DEBUG 04-08 20:31:55,009 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-08 20:31:55,029 <== Total: 1 (BaseJdbcLogger.java:145)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-08 20:31:55,030 put added 0 on heap (Segment.java:425)
DEBUG 04-08 20:31:55,031 Cache Hit Ratio [com.atguigu.mybatis.dao.EmployeeMapper]: 0.5 (LoggingCache.java:62)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
true
第二次是从二级缓存中拿到的数据,并没有发送sql。即第一次查询了2号员工,存在了EmployeeMapper中的缓存中,关闭了会话以后,第二次查询2好员工是从EmployeeMapper对应的缓存中取出
@Test
public void testSecondLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
Employee emp1 = mapper1.getEmpById(2);
System.out.println(emp1);
sqlSession1.close();
// 添加一条记录
mapper2.addEmp(new Employee(3, "dog", "1", "[email protected]", null));
Employee emp2 = mapper2.getEmpById(2);
System.out.println(emp1);
sqlSession2.close();
System.out.println(emp1 == emp2);
}finally {
}
}
DEBUG 04-08 21:07:00,463 Initialised cache: com.atguigu.mybatis.dao.EmployeeMapper (Cache.java:1165)
DEBUG 04-08 21:07:00,463 CacheDecoratorFactory not configured for defaultCache. Skipping for 'com.atguigu.mybatis.dao.EmployeeMapper'. (ConfigurationHelper.java:354)
DEBUG 04-08 21:07:00,476 Cache Hit Ratio [com.atguigu.mybatis.dao.EmployeeMapper]: 0.0 (LoggingCache.java:62)
DEBUG 04-08 21:07:00,609 ==> Preparing: select * from tbl_employee where id = ? (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,634 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,644 <== Total: 1 (BaseJdbcLogger.java:145)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-08 21:07:00,645 put added 0 on heap (Segment.java:425)
DEBUG 04-08 21:07:00,647 ==> Preparing: insert into tbl_employee(last_name, gender, email) values(?, ?, ?) (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,647 ==> Parameters: dog(String), 1(String), dog@qq.com(String) (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,648 <== Updates: 1 (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,649 Cache Hit Ratio [com.atguigu.mybatis.dao.EmployeeMapper]: 0.5 (LoggingCache.java:62)
DEBUG 04-08 21:07:00,649 ==> Preparing: select * from tbl_employee where id = ? (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,649 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-08 21:07:00,650 <== Total: 1 (BaseJdbcLogger.java:145)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
false
每个增删改标签的flushCache默认为true, 增删改完成后就会清除一级缓存(同时验证了上面一级缓存的情况3)和二级缓存。有个细节,第二次查询的时候会再次查询二级缓存,没查询到然后发送的sql
@Test
public void testSecondLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
Employee emp1 = mapper1.getEmpById(2);
System.out.println(emp1);
sqlSession1.close();
// 清空一级缓存
sqlSession2.clearCache();
Employee emp2 = mapper2.getEmpById(2);
System.out.println(emp1);
sqlSession2.close();
System.out.println(emp1 == emp2);
}finally {
}
}
DEBUG 04-08 21:16:17,251 Initialised cache: com.atguigu.mybatis.dao.EmployeeMapper (Cache.java:1165)
DEBUG 04-08 21:16:17,251 CacheDecoratorFactory not configured for defaultCache. Skipping for 'com.atguigu.mybatis.dao.EmployeeMapper'. (ConfigurationHelper.java:354)
DEBUG 04-08 21:16:17,269 Cache Hit Ratio [com.atguigu.mybatis.dao.EmployeeMapper]: 0.0 (LoggingCache.java:62)
DEBUG 04-08 21:16:17,410 ==> Preparing: select * from tbl_employee where id = ? (BaseJdbcLogger.java:145)
DEBUG 04-08 21:16:17,427 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:145)
DEBUG 04-08 21:16:17,443 <== Total: 1 (BaseJdbcLogger.java:145)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
DEBUG 04-08 21:16:17,443 put added 0 on heap (Segment.java:425)
DEBUG 04-08 21:16:17,445 Cache Hit Ratio [com.atguigu.mybatis.dao.EmployeeMapper]: 0.5 (LoggingCache.java:62)
Employee{id=2, lastName='Mary', gender='1', email='Mary@google.com', dept=null}
true
第二次查询的数据来源于二级缓存,尽管在查询之前执行了sqlSession.clearCache();
中,可以设置name=localCacheScope :本地缓存作用域(一级缓存session),value=SESSION:当前会话的所有数据保存在会话缓存中;value=STATEMENT:可以禁用一级缓存