zoukankan      html  css  js  c++  java
  • 05、MyBatis 缓存

    1.MyBatis缓存

      MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率.

     

    1).一级缓存

    	public Employee getEmpById(Integer id);
    

      

    	<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql" >
    		select * from tbl_employee where id = #{id}
    	</select>
    

      

    	@Test
    	public void testFirstLevelCache() throws IOException {
    		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    		SqlSession openSession = sqlSessionFactory.openSession();
    		try {
    			
    			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    			Employee emp01 = mapper.getEmpById(10);
    			System.out.println(emp01);
    			
    			//
    			Employee emp02 = mapper.getEmpById(1-0);
    			System.out.println(emp02);
    			System.out.println(emp01==emp02);
    			
    		}finally {
    			openSession.close();
    		}
    	}

    2).一级缓存失效情况

    (1).sqlSession不同

    (2).sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)

    (3).sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)

    (4).sqlSession相同,手动清除了一级缓存

    	public Employee getEmpById(Integer id);
    

      

    	<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql" >
    		select * from tbl_employee where id = #{id}
    	</select>
    

      

    	@Test
    	public void testFirstLevelCache() throws IOException {
    		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    		SqlSession openSession = sqlSessionFactory.openSession();
    		try {
    			
    			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    			Employee emp01 = mapper.getEmpById(10);
    			System.out.println(emp01);
    			
    			//1、Sqlsession不同
    //			SqlSession openSession2 = sqlSessionFactory.openSession();
    //			EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
    //			Employee emp02 = mapper2.getEmpById(10);
    			
    			//2、sqlSession相同,查询条件不同
    //			Employee emp02 = mapper.getEmpById(3);
    //			System.out.println(emp02);
    //			System.out.println(emp01==emp02);
    			
    			//3、sqlSession相同,两次查询之间执行了增删改操作
    //			mapper.addEmp(new Employee(null, "testCache", "cache@cache.com", "1"));
    //			System.out.println("数据添加成功");
    //			Employee emp02 = mapper.getEmpById(10);
    //			System.out.println(emp02);
    //			System.out.println(emp01==emp02);
    			
    			//4、sqlSession相同,手动清除了一级缓存
    			openSession.clearCache();
    			Employee emp02 = mapper.getEmpById(10);
    			System.out.println(emp02);
    			System.out.println(emp01==emp02);
    			
    		}finally {
    			openSession.close();
    		}
    	}
    

      

    3).二级缓存

      二级缓存(second level cache),全局作用域缓存.

      二级缓存默认不开启,需要手动配置.

      MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口.

      二级缓存在 SqlSession 关闭或提交之后才会生效.

    (1).二级缓存使用

    二级缓存使用:

    ①.开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>

    ②.去需要使用二级缓存的xml中配置使用二级缓存;添加<cache></cache>

    ③.POJO需要实现序列化接口

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

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
    	<!-- cache:使用二级缓存的namespace -->
    	<!-- eviction:缓存的清除策略;LRU|FIFO|SOFT|WEAK -->
    		<!-- LRU – 最近最少使用的:移除最长时间不被使用的对象。 -->
    		<!-- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 -->
    		<!-- SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。 -->
    		<!-- WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。 -->
    	<!-- flushInterval(刷新间隔):缓存多长时间清空一次,默认不清空,可以设置一个毫秒值启用刷新间隔 -->
    	<!-- readOnly(只读):属性可以被设置为 true 或 false -->
    		<!-- true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据; -->
    			<!-- 只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。 提供了可观的性能提升-->
    		<!-- false:非只读;mybatis觉得获取的数据可能会被修改; -->
    			<!-- 可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false -->
    	<!-- size(引用数目):属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源.默认值是 1024 -->
    	<!-- type:属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口.且提供一个接受 String 参数作为 id 的构造器 -->
    		<!-- 指定自定义缓存的全类名,实现Cache接口即可 -->
    	<!-- <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> -->
    	<cache></cache>
    </mapper>
    

      

    	@Test
    	public void testSecondLevelCache() throws IOException {
    		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    		SqlSession openSession = sqlSessionFactory.openSession();
    		SqlSession openSession2 = sqlSessionFactory.openSession();
    		try {
    			//1、
    			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    			EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
    			
    			Employee emp01 = mapper.getEmpById(1);
    			System.out.println(emp01);
    			openSession.close();
    			
    			//第二次查询是从二级缓存中拿到的数据,并没有发送新的sql
    			//mapper2.addEmp(new Employee(null, "aaa", "nnn", "0"));
    			Employee emp02 = mapper2.getEmpById(1);
    			System.out.println(emp02);
    			openSession2.close();
    		}finally {
    			
    		}
    	}
    

      

    (2).二级缓存工作原理

    二级缓存工作原理:

    ①.一个会话,查询一条数,这个数据就会被放在当前会话的一级缓存中;

    ②.如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;

    ③.不同namespace查出的数据会放在自己对应的缓存中(map):sqlSession===EmployeeMapper==>Employee|DepartmentMapper===>Department

    ④.二级缓存工作效果:查出的数据都会被默认先放在一级缓存中.只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中;

    (3).二级缓存属性设置

    ①.cacheEnabled="true|false": false关闭缓存(二级缓存关闭)(一级缓存一直可用的)

    ②.每个select标签都有useCache="true|false": false不使用缓存(一级缓存依然使用,二级缓存不使用)

    ③.*每个增删改标签的:flushCache="true|false":(一级二级都会清除)增删改执行完成后就会清楚缓存;

    测试:flushCache="true":一级缓存会被清空;二级也会被清空;每次查询之后都会清空缓存,缓存是没有被使用的;

    ④.sqlSession.clearCache();只是清除当前session的一级缓存

    ⑤.localCacheScope:本地缓存作用域;一级缓存SESSION;当前会话的所有数据保存在会话缓存中;STATEMENT:可以禁用一级缓存;

    /**

    * MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存

    * 一级缓存(本地缓存):sqlSession级别的缓存;一级缓存是一直开启的;SqlSession级别的一个Map

    * 与数据库同一次会话期间查询到的数据会放在本地缓存中;

    * 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;

    * 一级缓存失效情况:没有使用到一级缓存的情况,效果就是两次查询都需要向数据库发出查询

    * 1sqlSession不同

    * 2sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)

    * 3sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)

    * 4sqlSession相同,手动清除了一级缓存

    *

    * 二级缓存(全局缓存):基于namespace级别的缓存;一个namespace对应一个二级缓存;

    * 二级缓存工作原理:

    * 1、一个会话,查询一条数,这个数据就会被放在当前会话的一级缓存中;

    * 2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;

    * 3、不同namespace查出的数据会放在自己对应的缓存中(map):sqlSession===EmployeeMapper==>Employee|DepartmentMapper===>Department

    * 二级缓存工作效果:查出的数据都会被默认先放在一级缓存中.只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中;

    * 二级缓存使用:

    * 1、开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>

    * 2、去需要使用二级缓存的xml中配置使用二级缓存;添加<cache></cache>

    * 3POJO需要实现序列化接口

    *

    * 缓存有关属性/设置:

    * 1cacheEnabled="true|false": false关闭缓存(二级缓存关闭)(一级缓存一直可用的)

    * 2、每个select标签都有useCache="true|false": false不使用缓存(一级缓存依然使用,二级缓存不使用)

    * 3*每个增删改标签的:flushCache="true|false":(一级二级都会清除)增删改执行完成后就会清楚缓存;

    * 测试:flushCache="true":一级缓存会被清空;二级也会被清空;每次查询之后都会清空缓存,缓存是没有被使用的;

    * 4sqlSession.clearCache();只是清除当前session的一级缓存

    * 5localCacheScope:本地缓存作用域;一级缓存SESSION;当前会话的所有数据保存在会话缓存中;STATEMENT:可以禁用一级缓存;

    * @throws IOException

    */

    2.第三方缓存整合

      EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider.

      MyBatis定义了Cache接口方便我们进行自定义扩展. 

    参考文档:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

    http://mybatis.org/ehcache-cache/index.html

  • 相关阅读:
    Java 中的悲观锁和乐观锁的实现
    乐观锁和悲观锁的区别
    理解RESTful架构
    修复Linux下curl等无法使用 Let's Encrypt 证书
    呕心沥血 AR VR 好资源分享
    linux服务器出现大量TIME_WAIT的解决方法
    Ubuntu系统 无法删除 redis-server
    Python Flask jsonify a Decimal Error
    微信小程序 订阅消息 对接详细记录
    FTP时显示500 Illegal PORT command的解决
  • 原文地址:https://www.cnblogs.com/HOsystem/p/13152304.html
Copyright © 2011-2022 走看看