缓存
查询缓存主要是为了提高查询访问速度,即当用户执行一次查询后,会将该数据结果放到缓存中,当下次再执行此查询时就不会访问数据库了而是直接从缓存中获取该数据。 如果在缓存中找到了数据那叫做命中。 在mybatis中有一级缓存和二级缓存两种缓存方式。
一级缓存
MyBatis的一级查询缓存(也叫作本地缓存)是基于org.apache.ibatis.cache.impl.PerpetualCache 类的 HashMap本地缓存,其作用域是SqlSession,即在同一个SqlSession中两次执行相同的 sql 查询语句,第一次执行完毕后,会将查询结果写入到缓存中,第二次会从缓存中直接获取数据,而不再到数据库中进行查询,这样就减少了数据库的访问,从而提高查询效率。
当一个 SqlSession 结束后,该 SqlSession 中的一级查询缓存也就不存在了。 myBatis 默认一级查询缓存是开启状态,且不能关闭。
验证一级缓存
这里使用之前创建的t_student表,将StudentTest01类中将selectStudentById方法修改如下:
@Test
public void selectStudentById(){
Student student1 = studentDao.selectStudentById(2);
System.out.println(student1);
Student student2 = studentDao.selectStudentById(2);
System.out.println(student2);
}
执行结束后,在控制台中可以看到mybatis只发送了一条sql语句,也就是说上面方法中的第二次查询中使用了缓存中的数据。
mybatis是如何判断某个sql语句是否在缓存中存在呢?因为mapper中的id具有唯一性,所以mybatis是通过这个id来判断缓存中是否存在的。如果有两个sql语句一模一样,但是两者的id不一样,此时mybatis是不会为这两个sql语句建立相同缓存的。如果一条select语句中有查询条件的话,该查询条件也会被作为特征值,即再有相同条件查询的时候,会命中。
增删改对一级缓存的影响
这里就有一个问题,在第一次查询数据库后,mybatis会为selectStudentById建立缓存,那在下一次访问该数据的时候会直接从缓存中获取,倘若在这期间,建立缓存后,下次访问前,对数据进行了增删改的操作,此时无论是否commit,都会清空一级缓存。
将上面的测试方法修改如下:
@Test
public void selectStudentById(){
Student student1 = studentDao.selectStudentById(2);
System.out.println(student1);
//建立一级缓存后,对数据进行更新操作,会清空一级缓存
studentDao.updateStudent(student1);
//由于一级缓存已经被清空,此时会发送sql语句重新查询数据库
Student student2 = studentDao.selectStudentById(2);
System.out.println(student2);
}
执行该测试方法后可以发现在控制台中打印出了两条查询sql语句,一条update语句。