MyBatis(设置参数、延迟加载、缓存)
settings设置参数:
设置项 |
描述 |
允许值 |
默认值 |
cacheEnabled |
对在此配置文件下的所有cache 进行全 局性开/关设置。 |
true | false |
true |
lazyLoadingEnabled |
全局性设置懒加载。如果设为‘关’, 则所有相关联的都会被初始化加载。 |
true | false |
true |
aggressiveLazyLoading |
当设置为‘开’的时候,懒加载的对象 可能被任何懒属性全部加载。否则,每 个属性都按需加载。 |
true | false |
true |
multipleResultSetsEnabled |
允许和不允许单条语句返回多个数据 集(取决于驱动需求) |
true | false |
true |
useColumnLabel |
使用列标签代替列名称。不用的驱动器 有不同的作法。参考一下驱动器文档, 或者用这两个不同的选项进行测试一 下。 |
true | false |
true |
useGeneratedKeys |
允许JDBC 生成主键。需要驱动器支持。 如果设为了true,这个设置将强制使用 被生成的主键,有一些驱动器不兼容不 过仍然可以执行。 |
true | false |
False |
autoMappingBehavior |
指定MyBatis 是否并且如何来自动映射 数据表字段与对象的属性。PARTIAL 将只自动映射简单的,没有嵌套的结 果。FULL 将自动映射所有复杂的结果。 |
NONE, PARTIAL, FULL |
PARTIAL |
defaultExecutorType |
配置和设定执行器,SIMPLE 执行器执 行其它语句。REUSE 执行器可能重复 使用prepared statements 语句,BATCH 执行器可以重复执行语句和批量更新。 |
SIMPLE REUSE BATCH |
SIMPLE |
defaultStatementTimeout |
设置一个时限,以决定让驱动器等待数 据库回应的多长时间为超时 |
正整数 |
Not Set (null) |
mybatis的延迟加载
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息。
要设置延迟加载,需要在SqlMapConfig.xml文件中,在<settings>标签中设置下延迟加载:lazyLoadingEnabled、aggressiveLazyLoading
代码演示如下:
<!-- 开启延迟加载 --> <settings> <!-- lazyLoadingEnabled:延迟加载启动,默认是false --> <setting name="lazyLoadingEnabled" value="true" /> <!-- aggressiveLazyLoading:积极的懒加载,false的话按需加载,默认是true --> <setting name="aggressiveLazyLoading" value="false" /> </settings>
mybatis的缓存
许多应用程序,为了提高性能而增加缓存, 特别是从数据库中获取的数据.mybatis中对于缓存的使用,类似于hibernate的缓存机制,分为一级缓存和二级缓存
1.mybatis的一级缓存
mybatis的一级缓存是基于sqlSession的。
在同一个连接范围内,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。
当执行SQL时两次查询中间发生了增删改操作或者数据库连接关闭,则SqlSession的缓存清空。
与hibernate的一级缓存不一样,mybatis的一级缓存,可以用于所有的查询(hibernate中的一级缓存只针对根据主键查对象,而mybatis中查询全部时一级缓存也有效)
一级缓存的原理如下图:
2.mybatis的二级缓存
如果要实现 mybatis 的二级缓存,一般来说有如下两种方式:
i.
采用 mybatis 内置的 cache 机制。
ii.
采用三方 cache 框架, 比如ehcache, oscache 等等.
mybatis内置的缓存机制
在 sql 语句映射文件中加入 <cache /> 语句 , 并且相应的实体类要实现 Serializable 接口,因为缓存说白了就是序列化与反序列化的过程,所以需要实现这个接口. 单纯的 <cache /> 表示如下意思:
1.所有在映射文件里的 select 语句都将被缓存。
2.所有在映射文件里 insert,update 和 delete 语句会清空缓存。
3.缓存使用“最近很少使用”算法来回收
4.缓存不会被设定的时间所清空。
5.每个缓存可以存储 1024 个列表或对象的引用(不管查询出来的结果是什么) 。
6.缓存将作为“读/写”缓存,意味着获取的对象不是共享的且对调用者是安全的。不会有其它的调用者或线程潜在修改。
对于mybatis中的二级缓存:
mybatis中二级缓存是基于mapper级别的。不同的实体映射文件,二级缓存是不共享的;
mybatis默认没有开启二级缓存;
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内;
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果;
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存;
二级缓存的原理图如下:
mybatis中应用二级缓存,操作步骤如下:
1. 在mybatis的配置文件中,开启二级缓存(cacheEnabled设置为 true).
在mybatis_config.xml文件中,设置如下:
<settings> <!-- 开启二级缓存,默认为false(默认二级缓存是关闭的) --> <setting name="cacheEnabled" value="true"/> </settings>
2. 在实体映射文件中,应用二级缓存:
<cache eviction='FIFO' flushInterval='60000' size='512' readOnly='true'/>
其中各项属性代表的含义为:
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
eviction配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
1. LRU – 最近最少使用的:移除最长时间不被使用的对象。
2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
3. 缓存对象执行序列化
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。
如果该类存在父类,那么父类也要实现序列化,类似如下写法:
public class Emp implements Serializable { ... }
至此,二级缓存可以使用了。
另外,在应用二级缓存过程中,我们还可以禁用二级缓存:
<!-- 查询全部员工信息 -->
<select id="findallEmp" resultType="cn.jbit.pojo.Emp" useCache="false">
select empno, ename, job, mgr, hiredate, sal, comm, deptno from emp
</select>
该statement中设置userCache=false可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存.
还可以刷新二级缓存:
<!-- 查询全部员工信息 -->
<select id="findallEmp" resultType="cn.jbit.pojo.Emp" flushCache="true">
select empno, ename, job, mgr, hiredate, sal, comm, deptno from emp
</select>
应用第三方缓存框架ehcache
ehcache是一个分布式缓存框架。
EhCache 是一个纯Java的进程内缓存框架,是一种广泛使用的开源Java分布式缓存,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类:
1. 准备jar包
可以到github上下载,路径如下:
https://github.com/mybatis/ehcache-cache/releases
下载后可以找到三个jar包:
1. mybatis-ehcache-1.0.3.jar
2. ehcache-core-2.6.8.jar
3. slf4j-api-1.6.1.jar
其中,mybatis本身已经带了slf4j-api包,所以只需要拷贝前两个jar包即可
2. 整合Ehcache
在项目的src目录下,新建ehcache.xml文件,文件内容如下:
<ehcache> <!--表示硬盘上保存缓存的位置。默认是临时文件夹。--> <diskStore path="java.io.tmpdir"/> <!--默认缓存配置,如果类没有做特定的设置,则使用这里配置的缓存属性。 maxInMemory - 设置缓存中允许保存的最大对象(pojo)数量 eternal -设置对象是否永久保存,如果为true,则缓存中的数据永远不销毁,一直保存。 timeToIdleSeconds - 设置空闲销毁时间。只有eternal为false时才起作用。表示从现在到上次访问时间如果超过这个值,则缓存数据销毁 timeToLiveSeconds-设置活动销毁时间。表示从现在到缓存创建时间如果超过这个值,则缓存自动销毁 overflowToDisk - 设置是否在超过保存数量时,将超出的部分保存到硬盘上。--> <defaultCache maxElementsInMemory="1500" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="300" overflowToDisk="true"/> <!-- 也可以通过name设置针对某个类的缓存配置 <cache name="cn.sz.po.Emp" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" />--> </ehcache>
这个ehcache.xml的写法与在hibernate中写法完全一致
3. sql映射文件中配置cache:
打开需要缓存的实体映射文件(比如Emp.xml),加上cache,并指定处理缓存的实现类:
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" > <property name="timeToIdleSeconds" value="3600"/> <property name="timeToLiveSeconds" value="3600"/> <!-- 同ehcache参数maxElementsInMemory--> <property name="maxEntriesLocalHeap" value="1000"/> <!-- 同ehcache参数maxElementsOnDisk --> <property name="maxEntriesLocalDisk" value="10000000"/> <property name="memoryStoreEvictionPolicy" value="LRU"/> </cache>
这个配置是会带上cache执行的日志,如果不要带日志可以把LogginEhcache改成EhcacheCache,如下:
<!-- 如果不需要缓存日志,也可以改为EhCacheCache --> <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
至此,ehcache缓存就配置起来了
另,如果与spring集成,除了需要完成上面的三步以外,还需要在spring的配置文件里面加上一段配置:
<bean id="manager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
最后,这个mapper.xml里面的操作是全局,默认为useCache="true" 都会有作用,
假如某个业务是不要缓存的,可以在当前业务下加上useCache="false"
mybatis与hibernate的区别:
1.缓存
2.mybatis需要自己编写sql;hibernate则是生成(不需要自己编写sql)
3.在项目需要更换数据库时,hibernate更容易切换,mybatis相对更加繁琐(因为不同数据库,sql写法可能有区别)
4.性能上,mybatis性能相对更好(因为直接执行现有的sql),hibernate性能相对较差(需要根据对象自动拼接sql)