MyBatis 是基于JDBC的封装,是数据库操作更加便捷;MyBatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化
在MyBatis引入缓存机制,用于提升MyBatis的检索效率
在MyBatis引入延迟加载机制,用于减少对数据库不必要的访问
缓存的工作原理
缓存,就是存储数据的内存
![](https://i-blog.csdnimg.cn/blog_migrate/deac92b47fba3e86bc88ee5680c2c986.png)
MyBatis 缓存
MyBatis缓存分为一级缓存和二级缓存
一级缓存
一级缓存也叫做SqlSession级缓存,为每个SqlSession对象单独分配的缓存内存,无需手动开启可直接使用;多个SQLSession的缓存是不共享的
特性:
如果多次查询使用的是同一个SqlSession对象,则第一次查询之后数据会存放到缓存,后续则直接访问缓存中存储的数据
如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致
当我们进行再次查询时想要跳过缓存直接查询数据库,则可以通过sqlSession.clearCache();来清除SQL Session的缓存
如果第一次查询之后第二次查询之前,使用当前的sqlsession执行了修改操作,此修改操作会使第一次查询并缓存的数据失效,因此第二次查询会再次访问数据库
测试代码:
@Test
publicvoidtestQueryMemberById() {
SqlSessionsqlSession1=MyBatisUtil.getFactory().openSession();
SqlSessionsqlSession2=MyBatisUtil.getFactory().openSession();
//SqlSession sqlSession1 = MyBatisUtil.getSqlSession();
//SqlSession sqlSession2 = MyBatisUtil.getSqlSession();
MemberDAOmemberDAO1=sqlSession1.getMapper(MemberDAO.class);
Membermember1=memberDAO1.queryMemberById(1);
System.out.println(member1);
member1.setMemberAge(99);
sqlSession1.clearCache();
System.out.println("---------------------");
MemberDAOmemberDAO2=sqlSession1.getMapper(MemberDAO.class);
Membermember2=memberDAO2.queryMemberById(1);
System.out.println(member2);
}
两次查询与数据库数据不一致问题
![](https://i-blog.csdnimg.cn/blog_migrate/59ce4de38867197d2e0f93ca6ca73b02.png)
二级缓存
二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的SqlSession可以共享二级缓存;
在服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享
特性:
二级缓存默认没有开启,需要在mybatis_config.xml 的setting标签中开启
二级缓存只能缓存实现序列化接口的对象
在mybatis-config.xml开启使用二级缓存
<settings>
<settingname="cacheEnabled"value ="true"/>
</settings>
在需要使用二级缓存的Mapper文件中配置cache标签使用功能二级缓存
<cachereadonly="true"/>
被缓存的实体类实现序列化接口
publicclassMemberimplementsSerializable{
privateintmemberId;
privateStringmemberNick;
privateStringmemberGender;
privateintmemberAge;
privateStringmemberCity;
}
测试
@Test
publicvoidtestQueryMemberById() {
SqlSessionFactoryfactory=MyBatisUtil.getFactory();
//1.多个SqlSession对象必须来自同一个SqlSessionFactory
SqlSessionsqlSession1=factory.openSession(true);
SqlSessionsqlSession2=factory.openSession(true);
System.out.println(sqlSession1==sqlSession2);
MemberDAOmemberDAO1=sqlSession1.getMapper(MemberDAO.class);
Membermember1=memberDAO1.queryMemberById(1);
System.out.println(member1);
sqlSession1.commit(); //2.第一次查询之后执行sqlSession1.commit(),会将当前SQL session的查询结果缓存到二级缓存
System.out.println("---------------------");
MemberDAOmemberDAO2=sqlSession1.getMapper(MemberDAO.class);
Membermember2=memberDAO2.queryMemberById(1);
System.out.println(member2);
}
查询操作的缓存开关
<selectid="queryMemberById"resultMap="MemberMap"useCache="false"> /*useCache 属性 表示我这个查询是否使用缓存,不使用缓存则在数据库查询*/
select member_id,member_nick,member_gender,member_age,member_city
from members
where member_id=#{memberId}
</select>