一.使用Ehcache的目的
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。Mybatis与Ehcache整合可以提高性能,降低数据库压力。
二.MyBatis中使用Ehcache
1. 所需jar包
ehcache-2.10.4.jar
mybatis-ehcache-1.0.3.jar
2. ehcache配置文件,文件名必须为ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
<!-- 缓存存放目录(此目录为放入系统默认缓存目录) -->
<diskStore path="java.io.tmpdir" />
<!-- <diskStore path="/usr/web/apache-tomcat-8.5.16/temp"/> -->
<!-- <diskStore path="D:/cache" /> -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" >
</defaultCache>
<cache name="userCache"
maxElementsInMemory="3000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
memoryStoreEvictionPolicy="LFU">
</cache>
</ehcache>
<!--
name:Cache的唯一标识
maxElementsInMemory:内存中最大缓存对象数
maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大
eternal:Element是否永久有效,一但设置了,timeout将不起作用
overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中
timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大
diskPersistent:是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)
-->
3. 在mybatis的mapper中启用
ehcache已经配置好了,之后我们只需要在需要缓存的mapper配置文件里面加入<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>,该查询语句得到的结果将会被缓存。
有两种写法:
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
第一个可以输出日志,第二个不输出日志。
<?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.transfar.vms.base.dao.IDeviceDao">
<!--ehcache已经配置好了,然后只需要在想要缓存的mapper配置文件里面加入以下内容,该查询语句得到的结果将会被缓存 -->
<!-- 以下两个<cache>标签都可以,第一个可以输出日志,第二个不输出日志 -->
<!--<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/> -->
<!--<cache type="org.mybatis.caches.ehcache.EhcacheCache"/> -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
<resultMap id="BaseResultMap" type="com.transfar.vms.base.model.Device">
<id property="ID" column="DEVICE_ID" jdbcType="NUMERIC" />
<result property="DISTRICT_ID" column="ORGID" jdbcType="NUMERIC" />
<result property="DEVICE_NO" column="DEVICE_CODE" jdbcType="VARCHAR" />
<result property="RE_DEVICE_NO" column="DEVICE_CODE_INSTEAD"
jdbcType="VARCHAR" />
<result property="DEVICE_SN" column="DEVICE_SN" jdbcType="VARCHAR" />
<result property="DEVICE_NAME" column="DEVICE_NAME" jdbcType="VARCHAR" />
<result property="DEVICE_SHORTNAME" column="DEVICE_NAME_PINYIN"
jdbcType="VARCHAR" />
<result property="DEVICE_SMALLTPYE_ID" column="DEVICE_TYPE_ID"
jdbcType="VARCHAR" />
<result property="DEVICE_TYPE_ID" column="DEVICE_TYPE_ID"
jdbcType="VARCHAR" />
<result property="DEVICE_TYPE_NAME" column="DEVICE_TYPE_NAME"
jdbcType="VARCHAR" />
<result property="STAKE_ID" column="STAKE_ID" jdbcType="NUMERIC" />
<result property="DEVICE_DIRECTION" column="DEVICE_DIRECTION"
jdbcType="VARCHAR" />
<result property="DEVICE_DIRECTION_NAME" column="DEVICE_DIRECTION_NAME"
jdbcType="VARCHAR" />
<result property="LONGITUDE" column="LONGITUDE" jdbcType="VARCHAR" />
<result property="LATITUDE" column="LATITUDE" jdbcType="VARCHAR" />
<result property="IP_ADDRESS" column="IP_ADDRESS" jdbcType="VARCHAR" />
<result property="PORT" column="PORT" jdbcType="VARCHAR" />
<result property="DEVICE_STATUS_ID" column="DEVICE_STATUS_ID"
jdbcType="VARCHAR" />
<result property="COMM_STATUS_ID" column="COMM_STATUS_ID"
jdbcType="VARCHAR" />
<result property="START_USING_TIME" column="START_USING_TIME"
jdbcType="TIMESTAMP" />
<result property="FILL_TIME" column="FILL_TIME" jdbcType="TIMESTAMP" />
<result property="MANAGER_UNIT_ID" column="MANAGER_UNIT_ID"
jdbcType="NUMERIC" />
<result property="MANUFACTURER_ID" column="MANUFACTURER_ID"
jdbcType="NUMERIC" />
<result property="BRAND" column="BRAND" jdbcType="VARCHAR" />
<result property="FAULT_NUM" column="FAULT_NUM" jdbcType="NUMERIC" />
<result property="FAULT_DAY_NUM" column="FAULT_DAY_NUM"
jdbcType="NUMERIC" />
<result property="FAULT_REASON" column="FAULT_REASON" jdbcType="VARCHAR" />
<result property="FAULT_LAST_DAY" column="FAULT_LAST_DAY"
jdbcType="TIMESTAMP" />
<result property="LAST_MODIFIED_TIME" column="LAST_MODIFIED_TIME"
jdbcType="TIMESTAMP" />
<result property="UPDATE_FLAG" column="UPDATE_FLAG" jdbcType="VARCHAR" />
</resultMap>
<!--基础属性 -->
<sql id="Base_Column_List">
DEVICE_ID,ORGID,DEVICE_CODE,DEVICE_CODE_INSTEAD,DEVICE_SN,DEVICE_NAME,
DEVICE_NAME_PINYIN,DEVICE_TYPE_ID,DEVICE_TYPE_NAME,STAKE_ID,DEVICE_DIRECTION,
DEVICE_DIRECTION_NAME,LONGITUDE,LATITUDE,IP_ADDRESS,PORT,DEVICE_STATUS_ID,COMM_STATUS_ID,
START_USING_TIME,FILL_TIME,MANAGER_UNIT_ID,MANUFACTURER_ID,BRAND,FAULT_NUM,FAULT_DAY_NUM,
FAULT_REASON,FAULT_LAST_DAY,LAST_MODIFIED_TIME,UPDATE_FLAG
</sql>
<select id="getVmsInfoByDB" parameterType="string" resultMap="BaseResultMap"
useCache="true">
select
<include refid="Base_Column_List" />
from b_device_info where DEVICE_CODE=#{deviceId}
</select>
</mapper>
二.修改ehcache.xml文件默认位置
ehcache.xml文件默认只能放在classpath下,如果因为项目需求,配置文件要放在指定的位置,则需要修改mybatis-ehcache-1.0.3.jar这个jar包的源码。
反编译这个jar包,里面有3个java类。
修改EhcacheCache.java这个类的源码。里面有一行代码:
private static final CacheManager CACHE_MANAGER = CacheManager.create();
用于拿到CacheManager。需要修改这个create()方法,用重载的create()方法,如下:
private static final CacheManager CACHE_MANAGER = CacheManager.create(EhcacheCache.class.getClassLoader().getResourceAsStream("conf/ehcache.xml"));
我指定我的ehcache.xml这个配置文件在classes/conf/ehcache.xml。具体位置可以自行修改。
然后重新打包成jar包就可以了,非常简单。
三.应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
五.局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
缓存都是实现了Cache这个接口.....
public class EhCache implements Cache{}