程序中为什么使用缓存?
  先了解一下缓存的概念:原始意义是指访问速度比一般随机存取存储器快的一种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都共享一个二级缓存,二级缓存中存储的是数据,当命中二级缓存时,通过存储的数据构造对象返回。查询数据的时候,查询的流程是二级缓存>一级缓存>数据库

Mybatis的一级缓存和二级缓存的理解以及用法的更多相关文章

  1. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  2. MyBatis 延迟加载,一级缓存,二级缓存设置

    什么是延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再去加载关联信息 ...

  3. mybatis高级(3)_延迟加载_深度延迟_一级缓存_二级缓存

    设置延迟加载需要在mybatis.xml中设置 注: 侵入式延迟加载为真时是延迟加载 侵入式延迟加载为假时是深度延迟加载 <!-- 延迟加载和深度延迟加载 --> <settings ...

  4. 9.Mybatis一级缓存和二级缓存

    所谓的缓存呢?其实原理很简单,就是在保证你查询的数据是正确的情况下,没有去查数据库,而是直接查找的内存,这样做有利于缓解数据库的压力,提高数据库的性能,Mybatis中有提供一级缓存和二级缓存. 学习 ...

  5. 八 mybatis查询缓存(一级缓存,二级缓存)和ehcache整合

    1       查询缓存 1.1     什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存.

  6. myBatis学习(9):一级缓存和二级缓存

    正如大多数持久层框架一样,MyBatis同样提供了一级缓存和二级缓存的支持 1. MyBatis一级缓存基于PerpetualCache的HashMap本地缓存,其存储作用域为 Session,默认情 ...

  7. mybatis 详解(九)------ 一级缓存、二级缓存

    上一章节,我们讲解了通过mybatis的懒加载来提高查询效率,那么除了懒加载,还有什么方法能提高查询效率呢?这就是我们本章讲的缓存. mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解 ...

  8. MyBatis从入门到放弃六:延迟加载、一级缓存、二级缓存

    前言 使用ORM框架我们更多的是使用其查询功能,那么查询海量数据则又离不开性能,那么这篇中我们就看下mybatis高级应用之延迟加载.一级缓存.二级缓存.使用时需要注意延迟加载必须使用resultMa ...

  9. Mybatis第八篇【一级缓存、二级缓存、与ehcache整合】

    Mybatis缓存 缓存的意义 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题. myba ...

  10. MyBatis 一级缓存,二级缓存,延迟加载设置

       1  什么是延迟加载  resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再 ...

随机推荐

  1. windows和linux下如何对拍

    对拍是各种计算机考试检查时必备工具,实际上十分强大,只要你的暴力没有写错就没有问题. 对拍的意思:(怎么有点语文课的意思雾) 对:看见'对'就可以知道有两个. 拍:就是把两个程序结果拍在一起,对照(有 ...

  2. vue教程(三)-slot\keep-alive的使用

    一.slot其实就是填坑操作,父组件传递dom结构,是vue提供的一种内置组件(组件知识请查看上篇博客内容) 写法:<slot></slot> 例子: var child = ...

  3. thinkphp 数据库操作

    //所有的数据中,查出某个字段$result = $music->field('music')->select();$hotlist = M('News')->where('stat ...

  4. mysql查看视图用户

    select `DEFINER` from  information_schema.VIEWS;

  5. pycharm remote debug

    换工作了好久没写blog了,堕落了,哈哈,发现了好的东西分享一下,和以前使用的pycharm的远程debug相比,更为方便,原理同步本地和远程的代码,加载远程的环境运行,使用本地的代码+远程的环境,方 ...

  6. python面向对象-封装-property-接口-抽象-鸭子类型-03

    封装 什么是封装: # 将复杂的丑陋的隐私的细节隐藏到内部,对外提供简单的使用接口 或 # 对外隐藏内部实现细节,并提供访问的接口 为什么需要封装 1.为了保证关键数据的安全性 2.对外部隐藏内部的实 ...

  7. tornado并发性能测试

    1.带server2.0装饰器 接口访问数据库查询 并发100 平均每秒处理11.8次请求 平均响应时间6944ms 接口不做任何处理 并发100 平均每秒处理99.9次请求 平均响应时间3ms 并发 ...

  8. Heap Greedy

    1 239 Sliding Window Maximun 双端队列 public int[] maxSlidingWindow(int[] nums, int k) { if (nums == nul ...

  9. 深入理解JVM-java字节码文件结构剖析(练习解读字节码)

    public class MyTest2 { String str = "Welcome"; private int x = 5; public static Integer in ...

  10. 深入理解JVM-类加载器深入解析(1)

    类加载 在java代码中,类型的加载,连接与初始化过程都是在程序运行期间完成的 类型:表示的Object本身,并不是指一个对象,也就是class. 运行期间:表示的是一种runtime的概念,在运行期 ...