码迷,mamicode.com
首页 > 其他好文 > 详细

MyBatis 之 缓存

时间:2015-09-21 18:02:27      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:

MyBatis 和 Hibernate 一样具有 一级缓存二级缓存

1.  一级缓存:MyBatis 一级缓存的作用域 是 同一个SqlSession

    写一个 查询 User 的例子:

  <!-- user 查询 -->
  <select id="findUserById" parameterType="int" resultType="user">
  	select * from users where userId = #{user_id}
  </select>
//测试一级缓存
@Test
public void testCache1() throws Exception {
	//获取SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();
		
	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
		
	//第一次查询
	User user = new User();
	user.setUserId(100108);
		
	System.out.println("-----------------第一次查询,从数据库获取--------------------");
	User getUser = orderMapper.findUserById(user.getUserId());
	System.out.println(getUser);
		
	System.out.println("-----------------第二次查询,从缓存中获取--------------------");
		
	//再次执行同样的查询
	User getUser2 = orderMapper.findUserById(user.getUserId());
	System.out.println(getUser2);
}

    执行结果:

    技术分享

    从结果中可以看出:第一次查询,在数据库中执行了 SQL。 而第二次并没有通过查询数据库得到结果,

    而是从缓存中获取的。那么缓存的机制是什么样的?

    SqlSession 缓存机制:执行一个SQL的时候,MyBatis 会首先去 缓存(PerpetualCache)中 根据 key 查询

    结果集,a. 如果没有则去查询数据库,查询成功后,将结果写入 cache 中;b. 如果有,则直接从缓存中

    取出结果集返回。

    MyBatis 内部存储 缓存使用的是一个 HashMap<CacheKey , Object>, key 为 hashCode + sqlId + Sql语句

    的格式, value 则是查询出来映射生成的 Java 对象。

    问题:如果在第二次查询之前,更新了这个 User 的信息,那么第二次查询是从缓存中取出数据还是再查询一次?

        结果是显而易见的,在 更新、删除操作的时,cache 会被清空。所以会再查询一次。

2.  二级缓存:即查询缓存,它的作用域是一个 mapper 的namespace,即在同一个 namespace 中的查询sql

     可以从缓存中获取数据。二级缓存是可以跨 SqlSession 的。

    a. 开启二级缓存:在SqlMapConfig.xml 的 <settings>...</settings>中加入

<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
  属性名   描述   允许值   默认值
cacheEnabled   对在此配置文件下所有的 cache 进行全局性开/关设置   true / false   true

    b. 在 mapper.xml 文件中添加 <cache /> 开启缓存

<mapper namespace="mybatis_b.mapper.OrderMapper">
  <!-- 开启本 mapper 的二级缓存 -->
  <cache />
</mapper>

    c. Java 调用,这里用两个 SqlSession 来实现二级缓存的跨 SqlSession

//测试二级缓存
@Test
public void testCache2() throws Exception {
	//获取SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();		
	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
		
	SqlSession sqlSession2 = sqlSessionFactory.openSession();
        OrderMapper orderMapper2 = sqlSession2.getMapper(OrderMapper.class);
		
	//第一次查询
	User user = new User();
	user.setUserId(100108);
		
	System.out.println("-----------------第一次查询,从数据库获取--------------------");
	User getUser = orderMapper.findUserById(user.getUserId());
	System.out.println(getUser);
		
	//关闭session1
	sqlSession.close();
		
	System.out.println("-----------------第二次查询,从缓存中获取--------------------");
		
	//再次执行同样的查询
	User getUser2 = orderMapper2.findUserById(user.getUserId());
	System.out.println(getUser2);
	sqlSession2.close();
}

    其中,User 类要实现序列化接口。执行后发现第二次的确是从缓存中获取数据的,结果就不贴了。

    问题:如果在 第一次查询完后,更新某个数据,那么第二次还会从缓存中获取数据吗?结果是否是最新?

    结果:第二次依旧是从缓存中获取的,而且是最新的。因为:在 mapper 的同一个 namespace 中,如果有

              其他 insert、update、delete 操作数据后需要刷新缓存,如果不执行则会出现脏读。而 mapper

              的sql 中有 flushCache="true" 这个属性,默认为 true即刷新 mapper 级别的缓存。

3. Cache 的其他参数:

    flushInterval:刷新间隔,可以设置为任意的正整数,表示一个合理的时间段,以毫秒为单位。默认情况是

                            不设置,也就是没有刷新间隔,仅在调用语句时刷新缓存。

    size:引用数目,可以设置为任意的正整数,要记住你缓存的对象和 运行环境的可用内存资源,默认值是1024

    readOnly:只读属性。只读的缓存会给所有的调用者返回缓存对象相同的实例。因此这些对象不能被修改。

                       这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些

                      ,但是安全,因此默认是false。

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

    上面这个缓存配置创建了一个FIFO缓存,并每隔60s刷新,存储结果对象或列表的512个引用,而且返回的

    对象被认为是只读的,因此在不同的线程中调用者之间修改它们会导致冲突。

    可用的回收策略有:

    A. LRU - 最近最少使用的:移除最长时间不被使用的对象

    B. FIFO - 先进先出:按对象进入缓存的顺序来移除它们。

    C. SOFT - 软引用:移除基于垃圾回收器状态和软引用规则的对象。

    D. WEAK - 弱引用:更积极地移除基于垃圾回收器状态和软引用规则的对象。

4. MyBatis 与 缓存框架 eacache 进行了整合,采用 eacache 框架管理缓存数据。

    a. 引入缓存的依赖包,需要 mybatis-ehcache-1.0.3.jar   ehcache-core-2.6.8.jar  和 slf4j-api-1.6.1.jar

    b. 修改 mapper 的缓存配置:

<!-- 以下两个<cache>标签二选一,第一个可以输出日志,第二个不输出日志 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

    有待详解。。。

MyBatis 之 缓存

标签:

原文地址:http://my.oschina.net/u/1757476/blog/509189

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!