1、关于数据缓存(Cache )
在应用程序中可使用缓存的环节是比较多的,对于如何来使用缓存,为什么要使用缓存以及生命时候使用缓存技术,有兴趣的小伙伴们可以去阅读其它大牛的技术文章或博客。我们今天只是对jfinal的数据缓存和插件使用做一个简单的科普。
缓存的使用主要还是要根据应用的特性来考虑。首先得分析应用的“变”与“不变”,哪些地方是主要用来展示的,数据操作的不是很频繁的话,那可以使用缓存来提升应用的性能。
EHCache 是一个纯java的在进程中的缓存,它具有以下特性:快速,简单。接下来我们一起来学习在jfinal中如何使用ehCache。
1.1下载jfinal框架中使用到的jar包
jar包下载地址:http://www.jfinal.com/download?file=jfinal-2.2-all.zip(需注册账号)
序列 | 名称 | 备注 |
---|---|---|
1、 | ehcache-core-2.5.2.jar | 缓存核心包 |
2、 | slf4j-api-1.6.1.jar | slf4j核心接口包 |
3、 | slf4j-log4j12-1.6.1.jar | slf4j调用log4j的实现包 |
1.2添加jar包到project(工程)
copy文件到projectName\WebRoot\WEB-INF\lib目录下。
1.3 添加ehcache.xml文件
copy文件到ehcache.xml文件到project中src路径下。
2、写一点代码使用cache
2.1我们来为数据读取作一个简单的数据缓存操作。翠花上代码:
/**
* @author yetangtang
* @see 查询用户信息
* @param void
* @return Page<Record> list
*/
public Page<Record> queryUsetrList(){
//使用Db中的paginate(分页)方法。同model操作一样
Page<Record> list = Db.paginateByCache("userInfo", "userList", 1, 4, "select * ","from user where id > ? ",2);
//Page<Record> list = Db.paginate(1, 4, "select * ","from user where id > ? ",2);
//返回查询结果
return list;
}
2.2配置ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="false" monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir"/>
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<!--默认使用的配置方式-->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="20"
timeToLiveSeconds="60">
</defaultCache>
<!--
Sample cache named sampleCache1
This cache contains a maximum in memory of 10000 elements, and will expire
an element if it is idle for more than 5 minutes and lives for more than
10 minutes.
If there are more than 10000 elements it will overflow to the
disk cache, which in this configuration will go to wherever java.io.tmp is
defined on your system. On a standard Linux system this will be /tmp"
-->
<!--demo中使用的配置,第一种-->
<cache name="userInfo"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off"
/>
<!--
Sample cache named sampleCache2
This cache has a maximum of 1000 elements in memory. There is no overflow to disk, so 1000
is also the maximum cache size. Note that when a cache is eternal, timeToLive and
timeToIdle are not used and do not need to be specified.
-->
<!--第二种配置方式-->
<cache name="sampleCache2"
maxEntriesLocalHeap="1000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="FIFO"
/>
<!--
Sample cache named sampleCache3. This cache overflows to disk. The disk store is
persistent between cache and VM restarts. The disk expiry thread interval is set to 10
minutes, overriding the default of 2 minutes.
-->
<!--第三种配置方式-->
<cache name="sampleCache3"
maxEntriesLocalHeap="500"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="1"
memoryStoreEvictionPolicy="LFU"
/>
</ehcache>
3、探讨实现
3.1查看方法
Db操作类中实现了三种分页缓存方法,我们一起来看一下第一种。第一个参数是cacheName缓存名称,第二个是Object key(数据对象的名字,你可以这么理解),剩下的都比较熟悉,在此就略过。
/**
* Paginate by cache.
* @see #paginate(int, int, String, String, Object...)
* @return Page
*/
public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, paras);
}
3.2不知代码真面目,只缘身在代码外
/**
* Paginate by cache.
* @see #paginate(int, int, String, String, Object...)
* @return Page
*/
public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
//获取配置文件
ICache cache = config.getCache();
//尝试从缓存中获取数据对象信息
Page<Record> result = cache.get(cacheName, key);
//如果缓存中没有数据信息,则需要去执行查询;
//得到查询结果后,并将数据信息添加到缓存中。
if (result == null) {
result = paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);
cache.put(cacheName, key, result);
}
return result;
}
3.3眼见为实,断点测试一下
首次读取数据会执行恭喜,恭喜。至此,小伙伴们已经学会简单的使用缓存了。接下来,我们会继续玩一些好玩的技能点。
PS:缓存虽好,依旧多结合自己系统的实际情况考虑。
网友评论
如果有一个查询出来的数据库列表(极少改动)的话,我们可以将这个列表查询出来放到缓存里面,那么会涉及到一个问题,数据的及时性就没有那么高了.我这边有个方案是,在Interceptor拦截器中拦截对该表的增删改方法(通过注解到具体方法上效率更高),拦截方法里面清空该缓存,这样就可以做到及时同步数据库和缓存的功能了.大家觉得呢