您的位置:首页 > 其它

MyBatis学习(六)---高级应用(延迟加载、缓存)

2017-12-18 23:38 344 查看

MyBatis学习(六)—高级应用(延迟加载、缓存)

标签(空格分隔): MyBatis学习

延迟加载

需要查询关联信息时,使用mybatis延迟加载特性可有效的减少数据库压力,首次查询只查询主要信息,关联信息等用户获取时再加载.

开启延迟加载

在mybatis的全局配置文件中,需要开启延迟加载功能

<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>


lazyLoadingEnabled:默认值false,全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。

aggressiveLazyLoading:默认值true,当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载

一对一查询懒加载实现

1、po对象的设置和一对一映射的一致,也就是在po对象中设置一个属性为关联查询得对象

2、mapper.xml中的配置

2.1 设置一个查询

<select id="findOrdersList3" resultMap="userordermap2">
SELECT
orders.*
FROM
orders
</select>


2.2 关联查询

<!-- 订单信息resultmap -->
<resultMap type="Orders" id="userordermap2">
<id property="id" column="id"/>
<result property="user_id" column="user_id"/>
<result property="number" column="number"/>
<association property="user" javaType="User" select="findUserById" column="user_id"/>
</resultMap>


association:

select=”findUserById”:指定关联查询sql为findUserById

column=”user_id”:关联查询时将users_id列的值传入findUserById

当对象中需要使用的user属性时,才会发起关联查询。

一对多查询懒加载实现

一对多延迟加载的方法同一对一延迟加载,在collection标签中配置select内容

和一对一懒加载类似

小结

如果说不使用MyBatis的关联查询,怎么实现懒加载

其实很简单,定义两个不同的查询statementid。通过java的遍历,当需要用到关联的属性的时候,发起一个数据库查询操作

作用:

当需要查询关联信息时再去数据库查询,默认不去关联查询,提高数据库性能。

只有使用resultMap支持延迟加载设置。

缓存

Mybatis的查询缓存分一级缓存和二级缓存两种。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象

一级缓存

一级缓存的生命周期是一个SqlSession,当同一个SqlSession中两次执行相同的sql,输入参数也相同时,SqlSession在查询第一次的时候会将查询的结果保存到缓存的一个Map结构中,当第二次发起查询时,先默认到缓存中获取。SqlSession结束后,该缓存中的数据也随之被清空,MyBatis默认开启一级缓存



二级缓存

二级缓存是多个SqlSession共享的,作用域是mapper的同一个namespace中,不同的SqlSession两次执行同一个namespace下的sql,当查询完之后,会将结果缓存起来,第二次执行查询时,先查询该namespace下是否有缓存数据,有则直接返回,但为了保证没有脏读,SqlSession执行insert、update、delete操作之后,会清空二级缓存,MyBatis默认不开启二级缓存。



注意:二级缓存需要查询结果映射的pojo对象实现java.io.Serializable接口实现序列化和反序列化操作,注意如果存在父类、成员pojo都需要实现序列化接口

开启二级缓存

在核心配置文件SqlMapConfig.xml中加入

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


同时需要在mapper.xml中添加一个,表示namespace开启二级缓存

<cache />


其中可以设置该缓存的刷新规则。例如如下配置:

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


flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

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

readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:

1. LRU – 最近最少使用的:移除最长时间不被使用的对象。

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

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

4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象

禁用二级缓存

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">


刷新缓存

在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读.(手动修改数据库数据也会出现脏读)

如果不想执行完sql后清空缓存,可以在statement 中设置flushCache=”true”。

<insert id="insertUser" parameterType="user" flushCache="true">


mybatis和第三方缓存整合

我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)。不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发。所以要使用分布式缓存对缓存数据进行集中管理。

mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。



总结

应用场景

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。

实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定

局限性

mybatis二级缓存对细粒度的数据级别的缓存实现不好。当数据库中某一个数据的变更会清空整个域的缓存。解决此类问题需要在业务层根据需求对数据有针对性缓存,通过手动的将数据添加到第三方缓存中
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: