Mybatis学习总结五之缓存

MyBatis 是持久层框架,支持一级缓存和二级缓存

mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。

  1.  一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
  2.  二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
  3.  对于缓存数据更新机制,当某一个作用域(一级缓存/二级缓存)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被清空。

一级缓存

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

package com.aiit.test;

import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.aiit.pojo.User;


public class TestMyBatisDemo {
	/*
	 * 一级缓存: 也就Session级的缓存(默认开启)
	 */
	public static void main(String[] args) {

		String resource="mybatis.cfg.xml";

		InputStream inputStream = TestMyBatisDemo.class.getClassLoader().getResourceAsStream(resource);

		SqlSessionFactory factory = new  SqlSessionFactoryBuilder().build(inputStream);
		SqlSession session = factory.openSession();

		//1.查询
		String statement1 = "com.aiit.dao.UserMapper.selectOne";
		User user1 = session.selectOne(statement1,1);
		System.out.println("查询结果1: " + user1);
		 /*
                     必须是同一个Session,如果session对象已经close()过了就不可能用了 
        */
		user1 = session.selectOne(statement1,1);
		System.out.println("查询结果2: " + user1);
		session.close();
		/**
		 * session被关闭下面代码就没有结果,需要重新执行session = factory.openSession();
		 * user1 = session.selectOne(statement1,1);
		   System.out.println("查询结果3: " + user1); 
		 */
		session = factory.openSession();
		user1 = session.selectOne(statement1,1);
		System.out.println("查询结果4: " + user1);

  
		//3.修改   执行增删改时都会自动清除缓存,确保操作后和数据库一致
		String statement3 = "com.aiit.dao.UserMapper.updateOne";
		User user3 = new User(9, "中国");
		int updateResult = session.update(statement3, user3);
		System.out.println("修改成功"+updateResult);
        session.commit();
		session.close();
	}

}

特别注意的地方:

1.一级缓存: 也就Session级的缓存(默认开启)

2.  必须是同一个Session,如果session对象已经close()过了就不可能用了,需要重新session = factory.openSession();

3.一旦执行增删改,缓存将会被清除

二级缓存

 1.在mybatis.cfg.xml中开启二级缓存

<configuration>
    <settings>
        <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
        <setting name="cacheEnabled" value="true" />
        .....
    </settings>
    ....
</configuration>

2.UserMapper.xml在映射文件中开启二级缓存

具体配置 开启缓存cache、执行缓存useCache、刷新缓存flushCache

<?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="com.aiit.dao.UserMapper">

<!--开启本mapper的namespace下的二级缓存-->
   <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

 <!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->   
	<select id="selectOne" parameterType="int" resultType="com.aiit.pojo.User"  useCache="true">
		SELECT * FROM tbl_user WHERE tbl_user.id=#{id}
	</select>
	

 <!--刷新二级缓存 flushCache
   <select id="selectOne" parameterType="int" resultType="com.aiit.pojo.User"  flushCache="true">
		SELECT * FROM tbl_user WHERE tbl_user.id=#{id}
	</select>
    -->	
</mapper>

3.使用二级缓存时,User类必须实现一个Serializable接口===> User implements Serializable

4.测试二级缓存
     使用两个不同的SqlSession对象去执行相同查询条件的查询,第二次查询时不会再发送SQL语句,而是直接从缓存中取出数据

package com.aiit.test;

import java.io.InputStream;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.aiit.pojo.User;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		String resource="mybatis.cfg.xml";
		InputStream inputStream = Test.class.getClassLoader().getResourceAsStream(resource);
		SqlSessionFactory factory = new  SqlSessionFactoryBuilder().build(inputStream);
		//开启两个不同的SqlSession
		
		SqlSession session1 = factory.openSession();
		SqlSession session2 = factory.openSession();
		
		String statement1 = "com.aiit.dao.UserMapper.selectOne";			
		User user1 = session1.selectOne(statement1,1);				
		//一定要提交事务之后二级缓存才会起作用		
		 session1.commit();	
		System.out.println("查询结果1: " + user1);
		
	    //由于使用的是两个不同的SqlSession对象,所以即使查询条件相同,一级缓存也不会开启使用	
		user1 = session2.selectOne(statement1,1);	
		System.out.println("查询结果1: " + user1);
	}

}

5.验证我们可以根据两条查询语句的时间,查看是否执行缓存

long startTime = System.currentTimeMillis();    //获取开始时间

User user1 = session1.selectOne(statement1,1);    //测试的代码段

long endTime = System.currentTimeMillis();    //获取结束时间
long time = endTime - startTime ;
System.out.println("查询时间: " + time );

特别注意:

    1. 映射语句文件中的所有select语句将会被缓存。

  2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。

  3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。

  4. 缓存会根据指定的时间间隔来刷新。

  5. 缓存会存储1024个对象

cache标签

<cache 
eviction="FIFO"  <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512" <!--最多缓存512个引用对象-->
readOnly="true"/> <!--只读-->

1.eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。 

     (1) LRU,最近最少使用的,一处最长时间不用的对象

     (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们  

     (3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象

     (4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,移除最长时间不用的对形象

2. flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当SQL被执行的时候才会去刷新缓存。

 3.size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。

 4. readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有办法修改缓存,他的默认值是false,不允许我们修改。

猜你喜欢

转载自blog.csdn.net/qq_38720976/article/details/84699912