EHCache是来自sourceforge(http://ehcache.sourceforge.net/)的开源项目,也是纯Java实现的简单、快速的Cache组件。

下载jar包

Ehcache 对象、数据缓存:http://ehcache.org/downloads/destination?name=ehcache-core-2.5.2-distribution.tar.gz&bucket=tcdistributions&file=ehcache-core-2.5.2-distribution.tar.gzWeb页面缓存:http://ehcache.org/downloads/destination?name=ehcache-web-2.0.4-distribution.tar.gz&bucket=tcdistributions&file=ehcache-web-2.0.4-distribution.tar.gz

需要添加如下jar包到lib目录下

ehcache-core-2.5.2.jarehcache-web-2.0.4.jar 主要针对页面缓存

当前工程的src目录中加入配置文件

ehcache.xmlehcache.xsd这些配置文件在ehcache-core这个jar包中可以找到

EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分布式的Cache,可以作为Hibernate/Spring等技术的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速度。

EHCache API的基本用法
  首先介绍CacheManager类。它主要负责读取配置文件,默认读取CLASSPATH下的ehcache.xml,根据配置文件创建并管理Cache对象。

// 使用默认配置文件创建CacheManager
CacheManager manager = CacheManager.create();
// 通过manager可以生成指定名称的Cache对象
Cache cache = cache = manager.getCache("demoCache");
// 使用manager移除指定名称的Cache对象
manager.removeCache("demoCache");
//可以通过调用manager.removalAll()来移除所有的Cache。
//通过调用manager的shutdown()方法可以关闭CacheManager。

有了Cache对象之后就可以进行一些基本的Cache操作,例如:

//往cache中添加元素
Element element = new Element("key", "value");
cache.put(element);
//从cache中取回元素
Element element = cache.get("key");
element.getValue();
//从Cache中移除一个元素
cache.remove("key");

可以直接使用上面的API进行数据对象的缓存,这里需要注意的是对于缓存的对象都是必须可序列化的。

在下面的篇幅中还会介绍EHCache和Spring、Hibernate的整合使用。

配置文件介绍
配置文件ehcache.xml中命名为demoCache的缓存配置:

<cache name="demoCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" />

各配置参数的含义:

maxElementsInMemory:缓存中允许创建的最大对象数
eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。
timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。
timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
overflowToDisk:内存不足时,是否启用磁盘缓存。
memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。LRU和FIFO算法这里就不做介绍。LFU算法直接淘汰使用比较少的对象,在内存保留的都是一些经常访问的对象。对于大部分网站项目,该算法比较适用。

如果应用需要配置多个不同命名并采用不同参数的Cache,可以相应修改配置文件,增加需要的Cache配置即可。

利用Spring APO整合EHCache

首先,在CLASSPATH下面放置ehcache.xml配置文件。在Spring的配置文件中先添加如下cacheManager配置:

<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
</bean>

配置demoCache:

<bean id="demoCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager" />
<property name="cacheName">
<value>demoCache</value>
</property>
</bean>

接下来,写一个实现org.aopalliance.intercept.MethodInterceptor接口的拦截器类。有了拦截器就可以有选择性的配置想要缓存的 bean 方法。如果被调用的方法配置为可缓存,拦截器将为该方法生成 cache key 并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次执行被拦截的方法,并缓存结果供下次调用。具体代码如下:

public class MethodCacheInterceptor implements MethodInterceptor,InitializingBean {private Cache cache;public void setCache(Cache cache) {this.cache = cache;}public void afterPropertiesSet() throws Exception {Assert.notNull(cache,"A cache is required. Use setCache(Cache) to provide one.");}public Object invoke(MethodInvocation invocation) throws Throwable {String targetName = invocation.getThis().getClass().getName();String methodName = invocation.getMethod().getName();Object[] arguments = invocation.getArguments();Object result;String cacheKey = getCacheKey(targetName, methodName, arguments);Element element = null;synchronized (this){element = cache.get(cacheKey);
      if (element == null) {//调用实际的方法result = invocation.proceed();element = new Element(cacheKey, (Serializable) result);cache.put(element);}}
    return element.getValue();}private String getCacheKey(String targetName, String methodName,Object[] arguments) {StringBuffer sb = new StringBuffer();sb.append(targetName).append(".").append(methodName);if ((arguments != null) && (arguments.length != 0)) {for (int i = 0; i < arguments.length; i++) {sb.append(".").append(arguments[i]);}}return sb.toString();}
}

synchronized (this)这段代码实现了同步功能。为什么一定要同步?Cache对象本身的get和put操作是同步的

如果我们缓存的数据来自数据库查询,在没有这段同步代码时,当key不存在或者key对应的对象已经过期时,在多线程并发访问的情况下,许多线程都会重新执行该方法,由于对数据库进行重新查询代价是比较昂贵的,而在瞬间大量的并发查询,会对数据库服务器造成非常大的压力。所以这里的同步代码是很重要的。

接下来,继续完成拦截器和Bean的配置:

<bean id="methodCacheInterceptor" class="com.xiebing.utils.interceptor.MethodCacheInterceptor"><property name="cache"><ref local="demoCache" /></property>
</bean>
<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice"><ref local="methodCacheInterceptor" /></property><property name="patterns"><list><value>.*myMethod</value></list></property>
</bean><bean id="myServiceBean" class="com.xiebing.ehcache.spring.MyServiceBean"></bean><bean id="myService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target"><ref local="myServiceBean" /></property><property name="interceptorNames"><list><value>methodCachePointCut</value></list></property>
</bean>

其中myServiceBean是实现了业务逻辑的Bean,里面的方法myMethod()的返回结果需要被缓存。这样每次对myServiceBean的myMethod()方法进行调用,都会首先从缓存中查找,其次才会查询数据库。使用AOP的方式极大地提高了系统的灵活性,通过修改配置文件就可以实现对方法结果的缓存,所有的对Cache的操作都封装在了拦截器的实现中。

CachingFilter功能
  使用Spring的AOP进行整合,可以灵活的对方法的的返回结果对象进行缓存。

  CachingFilter功能可以对HTTP响应的内容进行缓存

  这种方式缓存数据的粒度比较粗,例如缓存整张页面。它的优点是使用简单、效率高,缺点是不够灵活,可重用程度不高。
  EHCache使用SimplePageCachingFilter类实现Filter缓存。该类继承自CachingFilter,有默认产生cache key的calculateKey()方法,该方法使用HTTP请求的URI和查询条件来组成key。也可以自己实现一个Filter,同样继承CachingFilter类,然后覆写calculateKey()方法,生成自定义的key。
  在笔者参与的项目中很多页面都使用AJAX,为保证JS请求的数据不被浏览器缓存,每次请求都会带有一个随机数参数i。如果使用SimplePageCachingFilter,那么每次生成的key都不一样,缓存就没有意义了。这种情况下,我们就会覆写calculateKey()方法。

要使用SimplePageCachingFilter,首先在配置文件ehcache.xml中,增加下面的配置:

<cache name="SimplePageCachingFilter" maxElementsInMemory="10000" eternal="false"
overflowToDisk="false" timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" />

其中name属性必须为SimplePageCachingFilter,修改web.xml文件,增加一个Filter的配置:

<filter><filter-name>SimplePageCachingFilter</filter-name><filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
</filter>
<filter-mapping><filter-name>SimplePageCachingFilter</filter-name><url-pattern>/test.jsp</url-pattern>
</filter-mapping>

下面我们写一个简单的test.jsp文件进行测试,缓存后的页面每次刷新,在600秒内显示的时间都不会发生变化的。代码如下:

<%
out.println(new Date());
%>

  CachingFilter输出的数据会根据浏览器发送的Accept-Encoding头信息进行Gzip压缩。经过笔者测试,Gzip压缩后的数据量是原来的1/4,速度是原来的4-5倍,所以缓存加上压缩,效果非常明显。

在使用Gzip压缩时,需注意两个问题:

1. Filter在进行Gzip压缩时,采用系统默认编码,对于使用GBK编码的中文网页来说,需要将操作系统的语言设置为:zh_CN.GBK,否则会出现乱码的问题。
2. 默认情况下CachingFilter会根据浏览器发送的请求头部所包含的Accept-Encoding参数值来判断是否进行Gzip压缩。虽然IE6/7浏览器是支持Gzip压缩的,但是在发送请求的时候却不带该参数。为了对IE6/7也能进行Gzip压缩,可以通过继承CachingFilter,实现自己的Filter,然后在具体的实现中覆写方法acceptsGzipEncoding。

具体实现参考:

protected boolean acceptsGzipEncoding(HttpServletRequest request) {
final boolean ie6 = headerContains(request, "User-Agent", "MSIE 6.0");
final boolean ie7 = headerContains(request, "User-Agent", "MSIE 7.0");
return acceptsEncoding(request, "gzip") || ie6 || ie7;
}

EHCache在Hibernate中的使用
EHCache可以作为Hibernate的二级缓存使用。在hibernate.cfg.xml中需增加如下设置:

<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
</prop>

然后在Hibernate映射文件的每个需要Cache的Domain中,加入类似如下格式信息:

<cache usage="read-write|nonstrict-read-write|read-only" />

比如:

<cache usage="read-write" />

最后在配置文件ehcache.xml中增加一段cache的配置,其中name为该domain的类名。

<cache name="domain.class.name"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
/>

 EHCache的监控
  对于Cache的使用,除了功能,在实际的系统运营过程中,我们会比较关注每个Cache对象占用的内存大小和Cache的命中率。有了这些数据,我们就可以对Cache的配置参数和系统的配置参数进行优化,使系统的性能达到最优。EHCache提供了方便的API供我们调用以获取监控数据,其中主要的方法有:

//得到缓存中的对象数
cache.getSize();
//得到缓存对象占用内存的大小
cache.getMemoryStoreSize();
//得到缓存读取的命中次数
cache.getStatistics().getCacheHits()
//得到缓存读取的错失次数
cache.getStatistics().getCacheMisses()

分布式缓存
EHCache从1.2版本开始支持分布式缓存。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。具体的配置如下:

在配置文件ehcache.xml中加入

<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446"/><cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>

另外,需要在每个cache属性中加入

<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>

例如:

<cache name="demoCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>

简单完整例子: 

测试环境:

MySQL 5.0.22,
jdk1.6.0_07,
ehcache-1.6.0-beta2,
mysql-connector-java-3.1.14

测试表:

CREATE TABLE TEST
(
TEST_ID BIGINT,
TEST_NAME VARCHAR(50),
TEST_TIME TIMESTAMP,
TEST_VALUE DECIMAL(10, 3)
);

支持类:

public class Util {public static Random rand = new Random();public static String atoz = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";public static String genString(int length) {StringBuilder re = new StringBuilder(length);re.append(atoz.charAt(rand.nextInt(52)));for (int i = 0; i < length; i++) {re.append(atoz.charAt(rand.nextInt(62)));}return re.toString();}public static double genDouble() {double d1 = 5120 * rand.nextDouble();double d2 = 1024000 * rand.nextDouble();return d1 + d2;}
}

插入测试数据:

public static void traditionalInsert(int total) throws Exception {Thread.sleep(3000);Timestamp current = new Timestamp(System.currentTimeMillis());String currentStr = dateFormat.format(current);System.out.println(currentStr);Connection conn = DriverManager.getConnection(dbURL, user, pass);try {long begin = System.currentTimeMillis();conn.setAutoCommit(false);String sql = "INSERT INTO TEST (TEST_ID,TEST_NAME,TEST_TIME,TEST_VALUE) VALUES (?, ?, ?, ?)";PreparedStatement ps = conn.prepareStatement(sql);for (int i = 1; i <= total; i++) {ps.setLong(1, i);ps.setString(2, Util.genString(33));ps.setTimestamp(3, current);ps.setBigDecimal(4, new BigDecimal(Util.genDouble()));ps.addBatch();if ((i % 500) == 0) {ps.executeBatch();}}ps.executeBatch();conn.commit();long end = System.currentTimeMillis();System.out.printf("Count:%d Time:%d\n", total, (end - begin));} catch (Exception ex) {ex.printStackTrace();conn.rollback();} finally {conn.close();}}

使用的javaBean:

public class TEST implements Serializable {private static final long serialVersionUID = 1L;public Long TEST_ID;public String TEST_NAME;public Timestamp TEST_TIME;public BigDecimal TEST_VALUE;@Overridepublic String toString() {return String.format("ID:%s,,,NAME:%s", TEST_ID, TEST_NAME);}
}

先试一下缓存到字典中:

public static HashMap<Long, TEST> simpleCache() throws Exception {HashMap<Long, TEST> cacheid = new HashMap<Long, TEST>();Class.forName(dbDriver);Connection conn = DriverManager.getConnection(dbURL, user, pass);try {long begin = System.currentTimeMillis();Statement s = conn.createStatement();String sql = "SELECT TEST_ID,TEST_NAME,TEST_TIME,TEST_VALUE FROM TEST";ResultSet querySet = s.executeQuery(sql);for (int i = 1; querySet.next(); i++) {TEST curr = new TEST();curr.TEST_ID = querySet.getLong(1);curr.TEST_NAME = querySet.getString(2);curr.TEST_TIME = querySet.getTimestamp(3);curr.TEST_VALUE = querySet.getBigDecimal(4);cacheid.put(curr.TEST_ID, curr);}long end = System.currentTimeMillis();System.out.printf("Time:%d\n", (end - begin));} catch (Exception ex) {ex.printStackTrace();} finally {conn.close();}return cacheid;}

缓存到字典中,写法比较简单,使用方便,缺点就是缓存数据量比较少,一般缓存10W就有可能把jvm的缓存给占完了。用ehcache就可以解决缓存数据太少的问题。

一个简单的配置:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="ehcache.xsd"><diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="10000"maxElementsOnDisk="0"eternal="true"overflowToDisk="true"diskPersistent="false"timeToIdleSeconds="0"timeToLiveSeconds="0"diskSpoolBufferSizeMB="50"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LFU"/><cache name="demoCache"maxElementsInMemory="100"maxElementsOnDisk="0"eternal="false"overflowToDisk="false"diskPersistent="false"timeToIdleSeconds="119"timeToLiveSeconds="119"diskSpoolBufferSizeMB="50"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="FIFO"/>
</ehcache>

Cache配置中的几个属性:

name:Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)。
maxElementsInMemory:内存中保持的对象数量。
maxElementsOnDisk:DiskStore中保持的对象数量,默认值为0,表示不限制。
eternal:是否是永恒数据,如果是,则它的超时设置会被忽略。
overflowToDisk:如果内存中数据数量超过maxElementsInMemory限制,是否要缓存到磁盘上。
timeToIdleSeconds:对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
timeToLiveSeconds:对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。
diskExpiryThreadIntervalSeconds:对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。
diskSpoolBufferSizeMB:DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。
memoryStoreEvictionPolicy:如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。 

获取配置中的demoCache:

CacheManager manager = CacheManager.create("ehcache.xml");
Cache demo = manager.getCache("demoCache");

往cache中加入数据:

public static void ehcache() throws Exception {CacheManager manager = CacheManager.create("ehcache.xml");manager.addCache("TEST_ID.TEST");Cache cid = manager.getCache("TEST_ID.TEST");Class.forName(dbDriver);Connection conn = DriverManager.getConnection(dbURL, user, pass);try {long begin = System.currentTimeMillis();Statement s = conn.createStatement();String sql = "SELECT TEST_ID,TEST_NAME,TEST_TIME,TEST_VALUE FROM TEST";ResultSet querySet = s.executeQuery(sql);for (int i = 1; querySet.next(); i++) {TEST curr = new TEST();curr.TEST_ID = querySet.getLong(1);curr.TEST_NAME = querySet.getString(2);curr.TEST_TIME = querySet.getTimestamp(3);curr.TEST_VALUE = querySet.getBigDecimal(4);cid.put(new Element(curr.TEST_ID, curr));}long end = System.currentTimeMillis();System.out.printf("Time:%d\n", (end - begin));} catch (Exception ex) {ex.printStackTrace();} finally {conn.close();}}

这里在CacheManager中直接加入了一个叫TEST_ID.TEST的cache。因为只给了一个名字,所以系统会把defaultCache的设置给它clone一份。 
使用方法,像字典一样使用就行:

Cache cid = manager.getCache("TEST_ID.TEST");
Element e5120 = cid.get(new Long(5120));
System.out.println(e5120.getValue());

ehcache中数据是以java对象的形式存在的,使用了java的序列化保存到磁盘,所以保存的对象要实现Serializable接口。ehcache还可以支持分布式缓存。

总结
EHCache是一个非常优秀的基于Java的Cache实现。它简单、易用,而且功能齐全,并且非常容易与Spring、Hibernate等流行的开源框架进行整合。通过使用EHCache可以减少网站项目中数据库服务器的访问压力,提高网站的访问速度,改善用户的体验。

转载于:https://www.cnblogs.com/hwaggLee/p/4443127.html

缓存插件 EHCache相关推荐

  1. 三大缓存框架ehcache、memcache和redis的介绍

    三大缓存框架ehcache.memcache和redis的介绍 2016-04-12 架构说 4964 阅读 最近项目组有用到这三个缓存,去各自的官方看了下,觉得还真的各有千秋!今天特意归纳下各个缓存 ...

  2. Spring Boot 揭秘与实战(二) 数据缓存篇 - EhCache

    文章目录 1. EhCache 集成 2. 源代码 本文,讲解 Spring Boot 如何集成 EhCache,实现缓存. 在阅读「Spring Boot 揭秘与实战(二) 数据缓存篇 - 快速入门 ...

  3. 【转】最佳 WordPress 缓存插件:WP Super Cache

    WP Super Cache 是 WordPress 官方开发人员 Donncha 开发,是当前最高效也是最灵活的 WordPress 静态缓存插件.它把整个网页直接生成 HTML 文件,这样 Apa ...

  4. Spring 3.1:缓存和EhCache

    如果在网上查找使用Spring 3.1内置缓存的示例,那么通常会碰到Spring的SimpleCacheManager ,Spring的家伙说这对"用于测试或简单的缓存声明很有用" ...

  5. wordpress html页面缓存 cdn,WordPress 下老旧又高效的本地缓存插件 cos-html-cache

    摘要 Cos Html Cache是一种非常有效的WordPress页面缓存插件可以让你的站点更快更灵敏.基于URL重写,插件将自动生成HTML文件的帖子真正当他们第一次加载,并自动更新HTML文件. ...

  6. WordPress火箭缓存插件WP Rocket v3.8.8 汉化版

    简介: WordPress火箭缓存插件WP Rocket 网盘下载地址: http://kekewl.net/KqQXyi9KKLW0 图片:

  7. AJAX-Cache:一款好用的Ajax缓存插件

    原文链接 AJAX-Cache是什么 Ajax是前端开发必不可少的数据获取手段,在频繁的异步请求业务中,我们往往需要利用"缓存"提升界面响应速度,减少网络资源占用.AJAX-Cac ...

  8. Java的进程内缓存框架:EhCache (转)

    EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. Ehcache缓存的特点: 1. 快速. 2. 简单. 3. 多种缓存 ...

  9. 一个简单的Chrome浏览器“清理缓存”插件应用开发

    Chrome浏览器支持用户自定义安装丰富的插件来方便我们的使用,特别是对于一个码农来说,一些丰富的插件能够很方便我们的日常开发.本人就安装了许多方便的插件. 固然商店里有很多插件让我们去淘,但是如果我 ...

最新文章

  1. 给你一份长长长的 Spring Boot 知识清单(下)
  2. 在Dreamweaver中安装Emmet(zen-coding)
  3. Social Media Modify case - still about attribute_ref
  4. xshell 秘钥连接_如何使用PuTTY和xshell 分别远程连接linux,并配置秘钥认证
  5. 团结就是力量,TeamCola浅谈创业团队腾云驾雾的归国征程
  6. 采用Angular勾画SVG圆环形进度条
  7. 网络授时服务 NTP
  8. Android生命周期工具类,Android倒计时工具类
  9. 二维码扫描开源库ZXing定制化【转】
  10. 浅谈Borg/YARN/Mesos/Torca/Corona一类系统
  11. 数学建模国赛 2020B-穿越沙漠 第一关 Lingo 和 C语言 动态规划求解
  12. 盛大剥离新业务:陈大年控股
  13. 计算机网络题库与答案西电,西电计算机网络期末试题.doc
  14. Linux Ubuntu 安装五笔输入法 ibus-rime 教程
  15. 前缀树是什么 前缀树的使用场景
  16. PySide2多线程问题示例:创建新线程、子线程发射信号到主界面
  17. BUUCTF-刷题记录-8
  18. Unity之JSON(数据存储)
  19. 软件工程之七——软件维护
  20. Prism : Communicating Between Loosely Coupled Components

热门文章

  1. 2013 【第四届蓝桥杯省赛】 C/C++ B组
  2. 递归函数实现二进制转换为十进制
  3. JAVA权重算法(如Dubbo的负载均衡权重)
  4. 因为不允许对公司代码 XXXX科目 XXXXXXXXXX进行销项/进项税相关操作,所以税码XX无效
  5. IIS 编译器错误消息: CS0016未能写入输出文件“c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\roo
  6. PPIO数据碎片化分散存储
  7. python实战应用讲解-【numpy科学计算】scikits-statsmodels模块(附python示例代码)
  8. 【ECCV2018 UPDT】Unveiling the Power of Deep Tracking[特征融合]
  9. 运动耳机有必要买吗、口碑最好的运动耳机品牌排行
  10. mac zoc ssh工具