查看原文
其他

Mybatis的一级缓存和二级缓存的理解以及用法

点击上方 "程序员小乐"关注公众号

每天早上8点20分,第一时间与你相约

每日英文

Starting today, every smile, the world in addition to the dead, are is too small.

从今天开始,每天微笑吧,世上除了生死,都是小事。


每日掏心话

最怕和自己在乎的人慢慢变远,变淡,变陌生的过程,真的是发自内心的疼。一见如故,再见陌路,有时候,有些人不需要说再见便已消失在你的生命里。


来自:全me村的希望 | 责编:乐乐

链接:cnblogs.com/hopeofthevillage/p/11427438.html

图片来自网络


往日回顾:手写迷你 SpringMVC 框架,看了都说好



   正文   


程序中为什么使用缓存?

先了解一下缓存的概念:原始意义是指访问速度比一般随机存取存储器快的一种RAM,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。对于我们编程来说,所谓的缓存,就是将程序或系统经常要调用的对象(临时数据)存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。这样做可以减少系统的开销,提高效率。

对缓存有了一定的了解以后就知道了使用缓存是为了减少和数据库的交互次数,提高执行效率。那么下一个问题来了。什么样的数据能使用缓存,什么样的数据不能使用?

这是我们使用缓存必须要明确的事情,实际上适用于缓存的数据:经常查询并且不经常改变的,并且的数据的正确与否对最终结果影响不大的、不适用于缓存的数据:经常改变的数据,数据的正确与否对最终
结果影响很大的。


Mybatis中的一级缓存和二级缓存到底缓存了什么,缓存了以后又有什么效果,缓存的数据什么时候会被清空?


一级缓存:它指的是Mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,的话直接拿出来用,当SqlSession对象消失时,mybatis的一级缓存也就消失了,同时一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit(),close等方法时,就会清空一级缓存。

二级缓存:他值得是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存,但是其中缓存的是数据而不是对象,所以从二级缓存再次查询出得结果的对象与
第一次存入的对象是不一样的。

通过简单的例子来加深理解一级缓存和二级缓存。


一级缓存


1.用户类

public class User implements Serializable{ private Integer id; private String username; private Date birthday; private String sex; private String address; get和set方法省略.....}

2.Dao层

public interface UserDao { /** * 查询所有的用户 * * @return */ List<User> findAll(); /** * 根据Id查询用户 * * @return */ User findById(Integer id); /** * 更新用户 * @param user */ void updateUser(User user);}

3.UserDao.xml映射文件

<mapper namespace="com.example.dao.UserDao"> <select id="findAll" resultType="com.example.domain.User"> SELECT * FROM USER; </select> <select id="findById" resultType="com.example.domain.User" parameterType="INT"> SELECT * FROM USER WHERE ID = #{ID} </select> <update id="updateUser" parameterType="com.example.domain.User"> update USER <set> <if test="username != null">username=#{username},</if> <if test="password != null">birthday=#{birthday},</if> <if test="sex != null">sex=#{sex},</if> <if test="address != null">address=#{address},</if> </set> where id=#{id} </update></mapper>


在以上三步中这是mybatis的单表操作,下面通过根据用户ID查询用户的操作来观察一级缓存生效与否的区别  


4.测试


(1)  命中一级缓存的情况

测试代码:

@Test public void findByIdTest(){ session = factory.openSession(); userDao = session.getMapper(UserDao.class); //第一次获取该用户 User user1 = userDao.findById(45); System.out.println(user1); 第二次获取该用户 User user2 = userDao.findById(45); System.out.println(user2); System.out.println(user1 == user2); session.close(); }

测试结果:

  

(2)对SqlSession进行清除缓存的操作,即清楚一级缓存,然后再次进行测试。

@Test public void findByIdTest(){ session = factory.openSession(); userDao = session.getMapper(UserDao.class); User user1 = userDao.findById(45); System.out.println(user1); // session.commit(); 调用SqlSession的commit方法清空缓存
user1.setUsername("更新用户"); user1.setAddress("更新地址"); userDao.updateUser(user1);//通过更新SqlSession清空缓存 User user2 = userDao.findById(45); System.out.println(user2); System.out.println(user1 == user2); session.close(); }

清空缓存的操作很多,可以都试试。测试结果:

二级缓存  

再看一下Mybatis二级缓存是如何使用的,第一步让Mybatis框架支持二级缓存(在Mybatis的主配置文件中配置),第二步让当前的映射文件支持二级缓存(在Dao.xml映射文件中配置),第三步让当前的方法支持二级缓存(在标签中配置)。根据这个步骤将上面的查询用户的接口通过配置改造为可以支持二级缓存的方法。

1.配置Mybatis框架支持二级缓存


<setting name="cacheEnabled" value="true"/>

2.配置UserDao.xml支持二级缓存


<cache/>

3.配置查询的方法支持二级缓存

<select id="findById" resultType="com.example.domain.User" parameterType="INT" useCache="true"> SELECT * FROM USER WHERE ID = #{ID} </select>

4.测试


@Test public void findByIdTest(){ //第一次查询 并更新二级缓存 SqlSession session1 = factory.openSession(); UserDao userDao1 = session1.getMapper(UserDao.class); User user1 = userDao1.findById(45); System.out.println(user1); session1.commit(); //commit()方法提交二级缓存 同时清空一级缓存 session1.close();//
// user1.setUsername("更新用户");// user1.setAddress("更新地址");// userDao.updateUser(user1);//通过更新SqlSession清空缓存 //第二次查找命中二级缓存 SqlSession session2 = factory.openSession(); UserDao userDao2 = session2.getMapper(UserDao.class); User user2 = userDao2.findById(45); session2.commit(); //commit()方法提交二级缓存 同时清空一级缓存 session2.close();// System.out.println(user2); System.out.println(user1 == user2); }

测试结果:

 

总结


mybatis的的一级缓存是SqlSession级别的缓存,一级缓存缓存的是对象,当SqlSession提交、关闭以及其他的更新数据库的操作发生后,一级缓存就会清空。二级缓存是SqlSessionFactory级别的缓存,同一个SqlSessionFactory产生的SqlSession都共享一个二级缓存,二级缓存中存储的是数据,当命中二级缓存时,通过存储的数据构造对象返回。查询数据的时候,查询的流程是二级缓存>一级缓存>数据库。

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。


欢迎各位读者加入程序员小乐技术群,在公众号后台回复“加群”或者“学习”即可。


猜你还想看


阿里、腾讯、百度、华为、京东最新面试题汇集

10个有难度的Java面试题(含答案)

为什么要前后端分离?有什么优缺点?

一篇文章告诉你 MVC、MVP 、MVVM

15 个超赞超牛逼的 Linux 工具,提高效率的同时增加乐趣!

Tomcat在SpringBoot中是如何启动的

关注「程序员小乐」,收看更多精彩内容
嘿,你在看吗?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存