1、查询缓存
Mybatis提供一级缓存和二级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象。在该对象中有一个数据结构(HashMap)用户存储缓存数据。
不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。
1.1、一级缓存
1.1.1、一级缓存工作原理
1.1.2、一级缓存测试
测试代码:(使用同一个sqlSession进行查询)
@Test
public void testFirstCache(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.findUserById(1);
User user1 = userDao.findUserById(1);
System.out.println(user);
System.out.println(user1);
}
测试结果:(查询结果相同,而且只生成一条sql语句,证明一级缓存存在)
1.2、二级缓存
1.2.1、二级缓存原理:
Mybatis是根据映射文件来开辟二级缓存的存储空间:使用哪个映射文件进行查询,就开辟哪一个映射文件的二级缓存。
使用多个映射文件查询的,根据namespace运行存储空间的开辟。
Mybatis查询获取原理:
第一次使用sql语句进行查询,首先检测二级缓存,如果二级缓存中没有,再检测一级缓存,如果一级缓存也没有,查询数据库。
第二次使用相同的sql语句进行查询,如果二级缓存开启的情况下,先检测二级缓存,如果二级缓存有,直接使用。
二级缓存数据存储结构:
Map结构:key是hashcode+sqlid+sql语句,value是存储查询值。
1.2.2、开启二级缓存
Mybatis的二级缓存是mapper级别的,除了需要在sqlMapConfig.xml中开启二级缓存,还需要在具体的mapper.xml中开启二级缓存。
☆注意:Mybatis缓存对应的pojo类要实现序列化接口(Serializable)
在核心配置文件中加入:
<?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="cacheEnabled" value="true"/>
</settings>
在具体的mapper.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="lsq.study.dao.UserDao">
<!-- 开启本mapper的namespace下的二级缓存 -->
<cache/>
<select id="findUserById" parameterType="int" resultType="lsq.study.domain.User">
select * from user where id = #{id}
</select>
</mapper>
1.2.3、测试代码
☆注意:sqlSession1要提交关闭,
@Test
public void testSecondCache(){
SqlSession sqlSession1 = sqlSessionFactory.openSession();
UserDao userDao1 = sqlSession1.getMapper(UserDao.class);
User user1 = userDao1.findUserById(1);
sqlSession1.commit();
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
User user2 = userDao2.findUserById(1);
System.out.println(user1);
System.out.println(user2);
}
测试结果:
1.2.4、useCache配置
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql语句查询,默认情况是true,即该sql使用二级缓存。
<select id = "..." resultMap="..." useCache="false">
总结:针对每次查询都需要最新数据的sql,要设置成useCache=false,禁用二级缓存。
1.2.5、刷新缓存
在mapper的同一个namespace中,如果有其他insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache="true"属性,默认情况下为true,即刷新缓存。如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
如下:
<insert id=" " parameterType=" " flushCache="true">
总结:一般情况下,执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。