与Hibernate一样,MyBatis 也提供了一级缓存和二级缓存的支持。
1、一级缓存:(本地缓存)SqlSession级别的缓存,默认一直开启的 ,
与数据库同一次会话期间的数据会放到本地缓存中,以后如果需要相同的数据,直接从缓存中拿,不再查询数据库。
当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
当进行增删改之后,该Session中的所有 Cache 就将清空。
2、二级缓存:基于namespace级别的缓存,一个namespace对应一个二级缓存
可自定义存储源,如 Ehcache。
当 Session flush 或 close 之后,二级缓存仍然可用。
当进行增删改之后,该namespace的所有 Cache 就将清空。
<setting name="cacheEnabled" value="false" />可关闭二级缓存,一级缓存可用。
一、一级缓存
package com.pjf.mybatis; import java.io.IOException; import java.io.InputStream;import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.pjf.mybatis.dao.HotelMapper; import com.pjf.mybatis.po.Hotel; public class TestHotel { public SqlSessionFactory sqlSessionFactory() throws IOException { String resource = "mybatis_config.xml"; InputStream is = Resources.getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); return sessionFactory; } /* * Mybatis缓存机制 * 一级缓存:(本地缓存)SqlSession级别的缓存,默认一直开启的 * 与数据库同一次会话期间的数据会放到本地缓存中 * 以后如果需要相同的数据,直接从缓存中拿,不再查询数据库 * 一级缓存的失效情况(需要重新发送sql) * 1、sqlSession不同 * 2、sqlSession相同,查询条件不同 * 3、sqlSession相同,查询条件相同,但两次查询之间执行了增删改操作 * 4、sqlSession相同,查询条件相同,手动清除了缓存clearCache() */ @Test public void testMybatisCache() throws IOException { SqlSessionFactory sessionFactory = sqlSessionFactory(); SqlSession session = sessionFactory.openSession(true); HotelMapper hotelMapper = session.getMapper(HotelMapper.class); Hotel hotel = hotelMapper.getHotel(1001); System.out.println(hotel); //第二次查询,条件一致 Hotel hotel2 = hotelMapper.getHotel(1001); System.out.println(hotel2); session.close(); } }
一级缓存在以下四种情况下会失效
1、sqlSession不同 2、sqlSession相同,查询条件不同 3、sqlSession相同,查询条件相同,但两次查询之间执行了增删改操作 4、sqlSession相同,查询条件相同,手动清除了缓存clearCache()
二、二级缓存
修改HotalMapper.xml文件
<?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.pjf.mybatis.dao.HotelMapper"> <!-- cache 缓存开启 eviction 缓存回售策略 LRU 最近最少使用的,移除最长时间不被使用的(默认) FIFO 先进先出 SOFT 软引用 WEAK 弱引用 flushInterval 缓存刷新间隔 缓存清空时间,默认不清空,设置毫秒值 readOnly 缓存是否只读 true mybatis只从缓存中毒数据,不会修改数据 false mybatis认为缓存中的数据会被修改,会用序列化和反序列化技术克隆一份给用户,安全,速度慢 size 缓存存放多少元素 type 指定自定义缓存的全类名 --> <cache eviction="LRU" flushInterval="60000" readOnly="false" size="1024" ></cache> <resultMap type="com.pjf.mybatis.po.Hotel" id="myHotel"> <id column="id" property="id" jdbcType="INTEGER" /> <result column="hotel_name" property="hotelName" jdbcType="VARCHAR" /> <result column="hotel_address" property="hotelAddress"jdbcType="VARCHAR" /> <result column="price" property="price" jdbcType="INTEGER" /> </resultMap> <select id="getHotel" resultMap="myHotel"> select* from hotel where id =#{id} </select> </mapper>
测试类
package com.pjf.mybatis; import java.io.IOException; import java.io.InputStream;import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.pjf.mybatis.dao.HotelMapper; import com.pjf.mybatis.po.Hotel; public class TestHotel { public SqlSessionFactory sqlSessionFactory() throws IOException { String resource = "mybatis_config.xml"; InputStream is = Resources.getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); return sessionFactory; } /* * 二级缓存:基于namespace级别的缓存,一个namespace对应一个二级缓存 * 工作机制: * 1、一个会话查询一个数据,这个数据会被保存到当前会话的一级缓存中 * 2、如果会话关闭,一级缓存中的数据会被保存到二级缓存中,新的会话消息,就可以查询二级缓存 * 3、不同namespace查出来的数据,会被放在自己对应的缓存中 * 使用: * 1、开启全局二级缓存配置 <setting name="cacheEnabled" value="true" /> * 2、去mapper.xml配置使用二级缓存 <cache></cache> * 3、pojo需要实现序列化接口 */ @Test public void testMybatisCache() throws IOException { SqlSessionFactory sessionFactory = sqlSessionFactory(); SqlSession session = sessionFactory.openSession(true); HotelMapper hotelMapper = session.getMapper(HotelMapper.class); Hotel hotel = hotelMapper.getHotel(1001); System.out.println(hotel); //关闭第一次会话 session.close(); //第二次查询 SqlSession session2 = sessionFactory.openSession(true); HotelMapper hotelMapper2 =session2.getMapper(HotelMapper.class); Hotel hotel2 = hotelMapper2.getHotel(1001); System.out.println(hotel2); session2.close(); } }
二级缓存使用的时候主要有三步:
1、开启全局二级缓存配置 <setting name="cacheEnabled" value="true" /> 2、去mapper.xml配置使用二级缓存 <cache></cache> 3、pojo需要实现序列化接口