MyBatis(6)——缓存

目录

一、一级缓存(本地缓存)

1、一级缓存

2、工作机制

3、一级缓存示例:

4、一级缓存失效情况及其生命周期

(1)失效情况

(2)生命周期

二、二级缓存(全局缓存)

1、工作机制

2、二级缓存的划分

3、使用二级缓存

(1)设置步骤:

(2)测试

(3)其他配置

三、第三方缓存框架——ehcache

1、整合步骤

2、测试


一、一级缓存(本地缓存)

1、一级缓存

一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改)

在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。为了解决这一问题,减少资源的浪费,MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中直接将结果取出,返回给用户,不需要再进行一次数据库查询了。

2、工作机制

由于MyBatis使用SqlSession对象表示一次数据库的会话,那么,对于会话级别的一级缓存也应该是在SqlSession中控制的。

实际上, MyBatis只是一个MyBatis对外的接口,SqlSession将它的工作交给了Executor执行器这个角色来完成,负责完成对数据库的各种操作。当创建了一个SqlSession对象时,MyBatis会为这个SqlSession对象创建一个新的Executor执行器,而缓存信息就被维护在这个Executor执行器中,MyBatis将缓存和对缓存相关的操作封装成了Cache接口中。

Executor接口的实现类BaseExecutor中拥有一个Cache接口的实现类PerpetualCache,则对于BaseExecutor对象而言,它将使用PerpetualCache对象维护缓存。

由于Session级别的一级缓存实际上就是使用PerpetualCache维护的,那么PerpetualCache是怎样实现的呢?PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v> 来实现的,没有其他的任何限制。

3、一级缓存示例:

测试代码:

@Test
public void testFirstLevelCache() throws IOException {
	String resource = "mybatis-config.xml";
	InputStream inputStream = Resources.getResourceAsStream(resource);
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	SqlSession session = sqlSessionFactory.openSession();
	try {
		EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
		Employee emp = mapper.selectEmployee(102);
		System.out.println(emp);

		Employee emp1 = mapper.selectEmployee(102);
		System.out.println(emp1);

		System.out.println(emp == emp1);
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		session.close();
	}
}

日志输出:

2018/12/30 19:29:23 DEBUG - Opening JDBC Connection 
2018/12/30 19:29:23 DEBUG - Checked out connection 936580213 from pool. 
2018/12/30 19:29:23 DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@37d31475] 
2018/12/30 19:29:23 DEBUG - ==>  Preparing: SELECT employee_id AS employeeId, first_name AS firstName, last_name AS lastName, email AS email, phone_number AS phoneNumber, hire_date AS hireDate, job_id AS jobId, salary AS salary, manager_id AS managerId, department_id AS departmentId FROM employee WHERE employee_id = ?  
2018/12/30 19:29:23 DEBUG - ==> Parameters: 102(Integer) 
2018/12/30 19:29:23 TRACE - <==    Columns: employeeId, firstName, lastName, email, phoneNumber, hireDate, jobId, salary, managerId, departmentId 
2018/12/30 19:29:23 TRACE - <==        Row: 102, Lex, De Haan, LDEHAAN, 515.123.4569, 2001-01-13, AD_VP, 17000.00, 100, 90 
2018/12/30 19:29:23 DEBUG - <==      Total: 1 
Employee [employeeId=102, firstName=Lex, lastName=De Haan, email=LDEHAAN, phoneNumber=515.123.4569, hireDate=Sat Jan 13 00:00:00 CST 2001, jobId=AD_VP, salary=17000.00, managerId=100, departmentId=90]
Employee [employeeId=102, firstName=Lex, lastName=De Haan, email=LDEHAAN, phoneNumber=515.123.4569, hireDate=Sat Jan 13 00:00:00 CST 2001, jobId=AD_VP, salary=17000.00, managerId=100, departmentId=90]
true

可以看出两次的查询,只发了一条sql,第二次的查询数据则是从缓存数据中获取。两个对象也是相同的。

4、一级缓存失效情况及其生命周期

(1)失效情况

1、SqlSession不同。
2、SqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
3、SqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
4、SqlSession相同,手动清除了一级缓存(缓存清空)

(2)生命周期

a. MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
b. 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
c. 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
d.SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;

参考及拓展:https://blog.csdn.net/luanlouis/article/details/41280959#t5

二、二级缓存(全局缓存)

二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

1、工作机制

当开一个会话时,一个SqlSession对象会使用一个Executor对象来完成会话操作,MyBatis的二级缓存机制的关键就是对这个Executor对象做文章。如果用户配置了"cacheEnabled=true",那么MyBatis在为SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:CachingExecutor,这时SqlSession使用CachingExecutor对象来完成操作请求。CachingExecutor对于查询请求,会先判断该查询请求在Application级别的二级缓存中是否有缓存结果,如果有查询结果,则直接返回缓存结果;如果缓存中没有,再交给真正的Executor对象来完成查询操作,之后CachingExecutor会将真正Executor返回的查询结果放置到缓存中,然后在返回给用户。

CachingExecutorExecutor的装饰者,以增强Executor的功能,使其具有缓存查询的功能,这里用到了设计模式中的装饰者模式。

2、二级缓存的划分

MyBatis并不是简单地对整个Application就只有一个Cache缓存对象,它将缓存划分的更细,即是Mapper级别的,即每一个Mapper都可以拥有一个Cache对象

(1)为每一个Mapper分配一个Cache缓存对象(使用<cache>节点配置);

(2)多个Mapper共用一个Cache缓存对象(使用<cache-ref>节点配置);

注意:

查出的数据都会被默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中。

而新的会话进来,会先到二级缓存进行查找数据,再去一级缓存中查找数据,最后是到数据库中查询数据。

3、使用二级缓存

(1)设置步骤:

1、开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>

2、mapper.xml中配置使用二级缓存:在Mapper文件中配置标签:<cache></cache>

cache标签的属性:

属性说明备注
eviction缓存的回收策略    • LRU – 最近最少使用的:移除最长时间不被使用的对象。
    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    • 默认的是 LRU。
 
flushInterval缓存刷新间隔缓存多长时间清空一次,默认不清空,设置一个毫秒值
readOnly是否只读• true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
• false:非只读:mybatis觉得获取的数据可能会被修改。mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢
size缓存存放多少元素; 
type指定自定义缓存的全类名 

3、POJO需要实现序列化接口

(2)测试

注意:第一个sqlSession1用完需要close,查询的数据才会写入二级缓存,否则还是停留在一级缓存。

@Test
public void testSecondLevelCache() throws IOException {
	String resource = "mybatis-config.xml";
	InputStream inputStream = Resources.getResourceAsStream(resource);
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	try {
		SqlSession sqlSession1 = sqlSessionFactory.openSession();
		EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
		Employee emp1 = mapper1.selectEmployee(102);
		System.out.println(emp1);
		sqlSession1.close();

		SqlSession sqlSession2 = sqlSessionFactory.openSession();
		EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
		Employee emp2 = mapper2.selectEmployee(102);
		System.out.println(emp2);

	} catch (Exception e) {
		e.printStackTrace();
	}
}

输出日志:

(3)其他配置

1、每个select标签都有useCache="true"。若值为 false:不使用缓存(一级缓存依然使用,二级缓存不使用),默认为true

2、每个增删改标签的flushCache="true"。insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。 设置statement配置中的flushCache=”true” 属性,默认情况下为true,即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。一级缓存就清空了;二级也会被清除;、

3、sqlSession.clearCache();只是清楚当前session的一级缓存

4、全局配置文件中的属性:localCacheScope,配置SESSION,则启用一级缓存,STATEMENT:可以禁用一级缓存。一般不作配置。

参考及拓展:https://blog.csdn.net/luanlouis/article/details/41408341

三、第三方缓存框架——ehcache

MyBatis缓存做的并不专业,用的是map。mybatis中默认自带的二级缓存有个弊端,即无法实现分布式缓存,什么意思呢?就是说缓存的数据在本地的服务器上,假设现在有两个服务器A和B,用户访问的时候访问了A服务器,查询后的缓存就会放在A服务器上,假设现在有个用户访问的是B服务器,那么,他在B服务器上就无法获取刚刚那个缓存。

mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。mybatis也默认实现了一个,但是这个缓存的实现无法实现分布式缓存,所以我们要自己来实现。ehcache分布式缓存就可以,mybatis提供了一个针对cache接口的ehcache实现类,这个类在mybatis和ehcache的整合包中。

ehcache是一个分布式缓存框架,EhCache 是一个纯Java的进程内缓存框架,是一种广泛使用的开源Java分布式缓存,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

1、整合步骤

进入MyBatis的github代码库(https://github.com/mybatis),找到ehcache-cache项目。

查看该项目的文档:http://www.mybatis.org/ehcache-cache/

(1)引入maven依赖:

<dependency>
	<groupId>org.mybatis.caches</groupId>
	<artifactId>mybatis-ehcache</artifactId>
	<version>1.1.0</version>
</dependency>

 (2)在Mapper文件进行配置:

指定自定义缓存的type:org.mybatis.caches.ehcache.EhcacheCache

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

(3)需要ehcache.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
 <!-- 磁盘保存路径 -->
 <diskStore path="D:\44\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="10000" 
   maxElementsOnDisk="10000000"
   eternal="false" 
   overflowToDisk="true" 
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 </defaultCache>
</ehcache>
 
<!-- 
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
 
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目 
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
 
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
 -->

2、测试

直接测试上方的二级缓存例子,查看日志输出:日志中会打印关于ehcache的初始化和缓存信息。

2018/12/30 22:41:51 DEBUG [org.apache.ibatis.logging.LogFactory] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Created connection 495792375. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Returned connection 495792375 to pool. 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.ConfigurationFactory] - Configuring ehcache from ehcache.xml found in the classpath: file:/E:/workspace-mars/MyBatisTest/target/classes/ehcache.xml 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.ConfigurationFactory] - Configuring ehcache from URL: file:/E:/workspace-mars/MyBatisTest/target/classes/ehcache.xml 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.ConfigurationFactory] - Configuring ehcache from InputStream 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.BeanHandler] - Ignoring ehcache attribute xmlns:xsi 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.BeanHandler] - Ignoring ehcache attribute xsi:noNamespaceSchemaLocation 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.DiskStoreConfiguration] - Disk Store Path: D:\cache\ehcache 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.CacheManager] - Creating new CacheManager with default config 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.util.PropertyUtil] - propertiesString is null. 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.ConfigurationHelper] - No CacheManagerEventListenerFactory class specified. Skipping... 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.Cache] - No BootstrapCacheLoaderFactory class specified. Skipping... 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.Cache] - CacheWriter factory not configured. Skipping... 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.ConfigurationHelper] - No CacheExceptionHandlerFactory class specified. Skipping... 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.store.MemoryStore] - Initialized net.sf.ehcache.store.MemoryStore for com.starfall.mybaits.dao.EmployeeMapper 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.DiskStorePathManager] - Using diskstore path D:\cache\ehcache 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.DiskStorePathManager] - Holding exclusive lock on D:\cache\ehcache\.ehcache-diskstore.lock 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.store.disk.DiskStorageFactory] - Failed to delete file com%002estarfall%002emybaits%002edao%002e%0045mployee%004dapper.index 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.store.disk.DiskStorageFactory] - Matching data file missing (or empty) for index file. Deleting index file D:\cache\ehcache\com%002estarfall%002emybaits%002edao%002e%0045mployee%004dapper.index 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.store.disk.DiskStorageFactory] - Failed to delete file com%002estarfall%002emybaits%002edao%002e%0045mployee%004dapper.index 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.Cache] - Initialised cache: com.starfall.mybaits.dao.EmployeeMapper 
 2018/12/30 22:41:52 DEBUG [net.sf.ehcache.config.ConfigurationHelper] - CacheDecoratorFactory not configured for defaultCache. Skipping for 'com.starfall.mybaits.dao.EmployeeMapper'. 
 2018/12/30 22:41:52 DEBUG [com.starfall.mybaits.dao.EmployeeMapper] - Cache Hit Ratio [com.starfall.mybaits.dao.EmployeeMapper]: 0.0 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC Connection 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Checked out connection 495792375 from pool. 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1d8d30f7] 
 2018/12/30 22:41:52 DEBUG [com.starfall.mybaits.dao.EmployeeMapper.selectEmployee] - ==>  Preparing: SELECT employee_id AS employeeId, first_name AS firstName, last_name AS lastName, email AS email, phone_number AS phoneNumber, hire_date AS hireDate, job_id AS jobId, salary AS salary, manager_id AS managerId, department_id AS departmentId FROM employee WHERE employee_id = ?  
 2018/12/30 22:41:52 DEBUG [com.starfall.mybaits.dao.EmployeeMapper.selectEmployee] - ==> Parameters: 102(Integer) 
 2018/12/30 22:41:52 TRACE [com.starfall.mybaits.dao.EmployeeMapper.selectEmployee] - <==    Columns: employeeId, firstName, lastName, email, phoneNumber, hireDate, jobId, salary, managerId, departmentId 
 2018/12/30 22:41:52 TRACE [com.starfall.mybaits.dao.EmployeeMapper.selectEmployee] - <==        Row: 102, Lex, De Haan, LDEHAAN, 515.123.4569, 2001-01-13, AD_VP, 17000.00, 100, 90 
 2018/12/30 22:41:52 DEBUG [com.starfall.mybaits.dao.EmployeeMapper.selectEmployee] - <==      Total: 1 
 Employee [employeeId=102, firstName=Lex, lastName=De Haan, email=LDEHAAN, phoneNumber=515.123.4569, hireDate=Sat Jan 13 00:00:00 CST 2001, jobId=AD_VP, salary=17000.00, managerId=100, departmentId=90]
2018/12/30 22:41:52 DEBUG [net.sf.ehcache.store.disk.Segment] - put added 0 on heap 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1d8d30f7] 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1d8d30f7] 
 2018/12/30 22:41:52 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Returned connection 495792375 to pool. 
 2018/12/30 22:41:52 DEBUG [com.starfall.mybaits.dao.EmployeeMapper] - Cache Hit Ratio [com.starfall.mybaits.dao.EmployeeMapper]: 0.5 
 Employee [employeeId=102, firstName=Lex, lastName=De Haan, email=LDEHAAN, phoneNumber=515.123.4569, hireDate=Sat Jan 13 00:00:00 CST 2001, jobId=AD_VP, salary=17000.00, managerId=100, departmentId=90]

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本工程用于研究如何借助Ehcache缓存框架实现对页面的缓存 本工程编码方式:UTF-8 本工程开发工具:MyEclipse 说明: 1、ehcache.xml和ehcache.xsd两个文件可以在下在下载下来的名为“ehcache-core-x.x.x-distribution.tar.gz”压缩文件中找到 2、由于要实现Ehcache缓存页面,所以必须要添加“ehcache-web-2.0.4.jar” jar包,该jar包主要用于辅助Ehcache实现页面缓存 注意: 本web工程的发布不要使用Tomcat7,否则会出现如下异常: 2015-3-25 9:53:50 org.apache.catalina.loader.WebappClassLoader loadClass 信息: Illegal access: this web application instance has been stopped already. Could not load net.sf.ehcache.store.disk.DiskStore$KeySet. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. java.lang.IllegalStateException at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1600) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559) at net.sf.ehcache.store.disk.DiskStore.keySet(DiskStore.java:560) at net.sf.ehcache.store.disk.DiskStorageFactory$DiskExpiryTask.run(DiskStorageFactory.java:838) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) 相关jar包下载地址: Ehcache 对象、数据缓存:http://ehcache.org/downloads/destination?name=ehcache-core-2.5.2-distribution.tar.gz&bucket=tcdistributions&file=ehcache

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值