一、 缓存的简单介绍
1.什么是缓存:
简单来说,缓存就是存在于内存中的临时数据。
2.为什么使用缓存:
减少和数据库的交互次数,提高执行效率。
3. 什么样的数据能使用缓存,什么样的数据不能使用
(1) 适用于缓存:
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。
(2) 不适用于缓存:
经常改变的数据
数据的正确与否对最终结果影响很大的。
4.什么是查询缓存
在内存或者外存上建立一个存储空间,用来保存上次查询结果,下次再进行同样的查询的时候,就可以直接从内存或者外存读取,不用再从数据库查找,提高速率。
二、MyBatis中常用的查询缓存。
1.一级缓存
一级缓存的范围是一个SqlSession对象:在同一个Sqlsession对象中多次执行相同的语句时,第一次执行完就会将数据库查询结果写到缓存(内存)中,以后再使用该执行语句,就会直接从缓存中查询。如果执行了commit()方法(增删改需要使用的方法),则SqlSession对象的一级缓存就会被清理。
使用前面的代码我们进行测试
public static void test1()throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory =new SqlSessionFactoryBuilder().build(reader);
SqlSession session =sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
//查询学号为101的学生
Student student1=st.findstudentbysn(101);
//第二次查询学号101的学生,直接从缓存中获取
Student student2=st.findstudentbysn(101);
session.close();
}
运行结果
可以发现,虽然测试方法中进行了两次查询,但是只发送了一次查询,第二次直接从缓存中查结果
加上commit()的方法再次进行测试。
public static void test2()throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory =new SqlSessionFactoryBuilder().build(reader);
SqlSession session =sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
//查询学号为101的学生
Student student1=st.findstudentbysn(101);
//执行一次修改方法,并调用conmint()方法
Student student3=new Student();
student3.setSn(101);
student3.setsname("李晓虎");
st.updatestudentbysn(student3);
session.commit();
//第二次查询学号101的学生,直接从缓存中获取
Student student2=st.findstudentbysn(101);
session.close();
}
查看结果
同样是查询两次,加入了comiit()方法后,清除了一级缓存,所以发送了两次查询语句。
2. 一级缓存
二级缓存可以是被多个Sqlsession对象共享的,范围是同一个namespace下SQL映射文件生成的动态代理mapper对象。同样,如果执行了commit()方法,二级缓存同样会被清除。此外,如果两个不同的SQL映射文件有相同的namespace的值,那么这两个namespace的SQL映射文件共同使用一个mapper对象。
二级缓存中,只要是使用了namespace相同的mapper对象,就只会在第一次查询是访问数据库并将结果写入二级缓存,以后再次查询时就可以直接从二级缓存中获取。
使用二级缓存
1.开启二级缓存
MyBatis没有默认开启二级缓存,需要在settings全局参数中开启。
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="cacheEnabled" value="true"/>
</settings>
SQL映射文件加上
<?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="dao.StudentDao">
<!-- 表示二级缓存功能打开-->
<cache/>
2.实现序列化
二级缓存需要使用实体类实现Java.io.Serializable接口,以支持序列化和反序列化操作。
3.测试二级缓存
运行测试方法:
public static void test3()throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory =new SqlSessionFactoryBuilder().build(reader);
//创建第一个session对象
SqlSession session1 =sessionFactory.openSession();
StudentDao st1=session1.getMapper(StudentDao.class);
//查询学号为101的学生
Student student1=st1.findstudentbysn(101);
session1.close();
//创建第二个session对象
SqlSession session2 =sessionFactory.openSession();
StudentDao st2=session2.getMapper(StudentDao.class);
//第二次查询学号101的学生,
Student student2=st2.findstudentbysn(101);
运行结果:
4.关闭二级缓存
<select id="findstudentbysn" parameterType="int" resultType="entity.Student" useCache="false">
select sname from student1 where sn=#{sn}
</select>
再次运行查看结果:
这里会执行两次查询。
5.清理二级缓存
在增删改后执行commit()方法,二级缓存就会被清除。
public static void test4()throws IOException{
String resource="conf.xml";
Reader reader=Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory =new SqlSessionFactoryBuilder().build(reader);
//创建第一个session对象
SqlSession session1 =sessionFactory.openSession();
StudentDao st1=session1.getMapper(StudentDao.class);
//查询学号为101的学生
Student student1=st1.findstudentbysn(101);
session1.close();
//执行更新方法
SqlSession session =sessionFactory.openSession();
StudentDao st=session.getMapper(StudentDao.class);
Student student3=new Student();
student3.setSn(101);
student3.setsname("李晓虎");
st.updatestudentbysn(student3);
session.commit();
//创建第二个session对象
SqlSession session2 =sessionFactory.openSession();
StudentDao st2=session2.getMapper(StudentDao.class);
//第二次查询学号101的学生,
Student student2=st2.findstudentbysn(101);
session2.close();
}
查看结果:
清除成功。