﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-昊天-随笔分类-EHCache</title><link>http://www.blogjava.net/hao446tian/category/48004.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 14 Oct 2011 14:00:50 GMT</lastBuildDate><pubDate>Fri, 14 Oct 2011 14:00:50 GMT</pubDate><ttl>60</ttl><item><title>hibernate二级缓存攻略</title><link>http://www.blogjava.net/hao446tian/archive/2011/10/14/361304.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Fri, 14 Oct 2011 09:57:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/10/14/361304.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/361304.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/10/14/361304.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/361304.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/361304.html</trackback:ping><description><![CDATA[<p>很多人对二级缓存都不太了解，或者是有错误的认识，我一直想写一篇文章介绍一下hibernate的二级缓存的，今天终于忍不住了。 <br />我的经验主要来自hibernate2.1版本，基本原理和3.0、3.1是一样的，请原谅我的顽固不化。</p>
<p>hibernate的session提供了一级缓存，每个session，对同一个id进行两次load，不会发送两条sql给数据库，但是session关闭的时候，一级缓存就失效了。</p>
<p>二级缓存是SessionFactory级别的全局缓存，它底下可以使用不同的缓存类库，比如ehcache、oscache等，需要设置hibernate.cache.provider_class，我们这里用ehcache，在2.1中就是 <br />hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider <br />如果使用查询缓存，加上 <br />hibernate.cache.use_query_cache=true</p>
<p>缓存可以简单的看成一个Map，通过key在缓存里面找value。</p>
<p><strong>Class的缓存</strong><br />对于一条记录，也就是一个PO来说，是根据ID来找的，缓存的key就是ID，value是POJO。无论list，load还是 iterate，只要读出一个对象，都会填充缓存。但是list不会使用缓存，而iterate会先取数据库select id出来，然后一个id一个id的load，如果在缓存里面有，就从缓存取，没有的话就去数据库load。假设是读写缓存，需要设置： <br />&lt;cache usage="read-write"/&gt; <br />如果你使用的二级缓存实现是ehcache的话，需要配置ehcache.xml <br />&lt;cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" /&gt; <br />其中eternal表示缓存是不是永远不超时，timeToLiveSeconds是缓存中每个元素（这里也就是一个POJO）的超时时间，如果eternal="false"，超过指定的时间，这个元素就被移走了。timeToIdleSeconds是发呆时间，是可选的。当往缓存里面put 的元素超过500个时，如果overflowToDisk="true"，就会把缓存中的部分数据保存在硬盘上的临时文件里面。 <br />每个需要缓存的class都要这样配置。如果你没有配置，hibernate会在启动的时候警告你，然后使用defaultCache的配置，这样多个class会共享一个配置。 <br />当某个ID通过hibernate修改时，hibernate会知道，于是移除缓存。 <br />这样大家可能会想，同样的查询条件，第一次先list，第二次再iterate，就可以使用到缓存了。实际上这是很难的，因为你无法判断什么时候是第一次，而且每次查询的条件通常是不一样的，假如数据库里面有100条记录，id从1到100，第一次list的时候出了前50个id，第二次 iterate的时候却查询到30至70号id，那么30-50是从缓存里面取的，51到70是从数据库取的，共发送1+20条sql。所以我一直认为 iterate没有什么用，总是会有1+N的问题。 <br />（题外话：有说法说大型查询用list会把整个结果集装入内存，很慢，而iterate只select id比较好，但是大型查询总是要分页查的，谁也不会真的把整个结果集装进来，假如一页20条的话，iterate共需要执行21条语句，list虽然选择若干字段，比iterate第一条select id语句慢一些，但只有一条语句，不装入整个结果集hibernate还会根据数据库方言做优化，比如使用mysql的limit，整体看来应该还是 list快。） <br />如果想要对list或者iterate查询的结果缓存，就要用到查询缓存了</p>
<p><strong>查询缓存</strong><br />首先需要配置hibernate.cache.use_query_cache=true <br />如果用ehcache，配置ehcache.xml，注意hibernate3.0以后不是net.sf的包名了 <br />&lt;cache name="net.sf.hibernate.cache.StandardQueryCache" <br />maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600" <br />timeToLiveSeconds="7200" overflowToDisk="true"/&gt; <br />&lt;cache name="net.sf.hibernate.cache.UpdateTimestampsCache" <br />maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/&gt; <br />然后 <br />query.setCacheable(true);//激活查询缓存 <br />query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion，可选 <br />第二行指定要使用的cacheRegion是myCacheRegion，即你可以给每个查询缓存做一个单独的配置，使用setCacheRegion来做这个指定，需要在ehcache.xml里面配置它： <br />&lt;cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" /&gt; <br />如果省略第二行，不设置cacheRegion的话，那么会使用上面提到的标准查询缓存的配置，也就是net.sf.hibernate.cache.StandardQueryCache</p>
<p>对于查询缓存来说，缓存的key是根据hql生成的sql，再加上参数，分页等信息（可以通过日志输出看到，不过它的输出不是很可读，最好改一下它的代码）。 <br />比如hql： <br />from Cat c where c.name like ? <br />生成大致如下的sql： <br />select * from cat c where c.name like ? <br />参数是"tiger%"，那么查询缓存的key*大约*是这样的字符串（我是凭记忆写的，并不精确，不过看了也该明白了）： <br />select * from cat c where c.name like ? , parameter:tiger% <br />这样，保证了同样的查询、同样的参数等条件下具有一样的key。 <br />现在说说缓存的value，如果是list方式的话，value在这里并不是整个结果集，而是查询出来的这一串ID。也就是说，不管是list方法还是iterate方法，第一次查询的时候，它们的查询方式很它们平时的方式是一样的，list执行一条sql，iterate执行1+N条，多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候，就都和iterate的行为一样了，根据缓存的key去缓存里面查到了value，value是一串id，然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。 <br />可以看出来，查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候，都是既填充查询缓存又填充class缓存的。 <br /><strong>这里还有一个很容易被忽视的重要问题，即打开查询缓存以后，即使是list方法也可能遇到1+N的问题！</strong>相同条件第一次list的时候，因为查询缓存中找不到，不管class缓存是否存在数据，总是发送一条sql语句到数据库获取全部数据，然后填充查询缓存和class缓存。但是第二次执行的时候，问题就来了，如果你的class缓存的超时时间比较短，现在class缓存都超时了，但是查询缓存还在，那么list方法在获取id串以后，将会一个一个去数据库load！因此，class缓存的超时时间一定不能短于查询缓存设置的超时时间！如果还设置了发呆时间的话，保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况，比如class缓存被程序强制evict了，这种情况就请自己注意了。</p>
<p>另外，如果hql查询包含select字句，那么查询缓存里面的value就是整个结果集了。</p>
<p>当hibernate更新数据库的时候，它怎么知道更新哪些查询缓存呢？ <br />hibernate在一个地方维护每个表的最后更新时间，其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。 <br />当通过hibernate更新的时候，hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表，当hibernate查询一个缓存是否存在的时候，如果缓存存在，它还要取出缓存的生成时间和这个缓存所查询的表，然后去查找这些表的最后更新时间，如果有一个表在生成时间后更新过了，那么这个缓存是无效的。 <br />可以看出，只要更新过一个表，那么凡是涉及到这个表的查询缓存就失效了，因此查询缓存的命中率可能会比较低。</p>
<p><strong>Collection缓存</strong><br />需要在hbm的collection里面设置 <br />&lt;cache usage="read-write"/&gt; <br />假如class是Cat，collection叫children，那么ehcache里面配置 <br />&lt;cache name="com.xxx.pojo.Cat.children" <br />maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" <br />overflowToDisk="true" /&gt; <br />Collection的缓存和前面查询缓存的list一样，也是只保持一串id，但它不会因为这个表更新过就失效，一个collection缓存仅在这个collection里面的元素有增删时才失效。 <br />这样有一个问题，如果你的collection是根据某个字段排序的，当其中一个元素更新了该字段时，导致顺序改变时，collection缓存里面的顺序没有做更新。</p>
<p><strong>缓存策略</strong><br />只读缓存（read-only）：没有什么好说的 <br />读/写缓存（read-write）:程序可能要的更新数据 <br />不严格的读/写缓存（nonstrict-read-write）：需要更新数据，但是两个事务更新同一条记录的可能性很小，性能比读写缓存好 <br />事务缓存（transactional）：缓存支持事务，发生异常的时候，缓存也能够回滚，只支持jta环境，这个我没有怎么研究过</p>
<p>读写缓存和不严格读写缓存在实现上的区别在于，读写缓存更新缓存的时候会把缓存里面的数据换成一个锁，其他事务如果去取相应的缓存数据，发现被锁住了，然后就直接取数据库查询。 <br />在hibernate2.1的ehcache实现中，如果锁住部分缓存的事务发生了异常，那么缓存会一直被锁住，直到60秒后超时。 <br />不严格读写缓存不锁定缓存中的数据。</p>
<p><strong>使用二级缓存的前置条件</strong><br />你的hibernate程序对数据库有独占的写访问权，其他的进程更新了数据库，hibernate是不可能知道的。你操作数据库必需直接通过 hibernate，如果你调用存储过程，或者自己使用jdbc更新数据库，hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的，但是据说3.1已经解决了这个问题。 <br />这个限制相当的棘手，有时候hibernate做批量更新、删除很慢，但是你却不能自己写jdbc来优化，很郁闷吧。 <br />SessionFactory也提供了移除缓存的方法，你一定要自己写一些JDBC的话，可以调用这些方法移除缓存，这些方法是： <br />void evict(Class persistentClass) <br />Evict all entries from the second-level cache. <br />void evict(Class persistentClass, Serializable id) <br />Evict an entry from the second-level cache. <br />void evictCollection(String roleName) <br />Evict all entries from the second-level cache. <br />void evictCollection(String roleName, Serializable id) <br />Evict an entry from the second-level cache. <br />void evictQueries() <br />Evict any query result sets cached in the default query cache region. <br />void evictQueries(String cacheRegion) <br />Evict any query result sets cached in the named query cache region. <br />不过我不建议这样做，因为这样很难维护。比如你现在用JDBC批量更新了某个表，有3个查询缓存会用到这个表，用evictQueries (String cacheRegion)移除了3个查询缓存，然后用evict(Class persistentClass)移除了class缓存，看上去好像完整了。不过哪天你添加了一个相关查询缓存，可能会忘记更新这里的移除代码。如果你的 jdbc代码到处都是，在你添加一个查询缓存的时候，还知道其他什么地方也要做相应的改动吗？</p>
<p>----------------------------------------------------</p>
<p><strong>总结：</strong><br />不要想当然的以为缓存一定能提高性能，仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的，不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用，可能会有1+N的问题。不当的使用还可能导致读出脏数据。 <br />如果受不了hibernate的诸多限制，那么还是自己在应用程序的层面上做缓存吧。 <br />在越高的层面上做缓存，效果就会越好。就好像尽管磁盘有缓存，数据库还是要实现自己的缓存，尽管数据库有缓存，咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么，只能做的比较通用，而高层可以有针对性的实现缓存，所以在更高的级别上做缓存，效果也要好些吧。</p><img src ="http://www.blogjava.net/hao446tian/aggbug/361304.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-10-14 17:57 <a href="http://www.blogjava.net/hao446tian/archive/2011/10/14/361304.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EhCache使用详细介绍</title><link>http://www.blogjava.net/hao446tian/archive/2011/05/24/350930.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Tue, 24 May 2011 08:20:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/05/24/350930.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/350930.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/05/24/350930.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/350930.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/350930.html</trackback:ping><description><![CDATA[<p>Ehcache中不仅可以用配置文件来配置缓存，而在代码中也可以实现同样的功能。 <br />CacheManager singletonManager = CacheManager.create(); <br />Cache memoryOnlyCache = new Cache(&#8220;testCache&#8221;, 50000, false, false, 8, 2); <br />Cache test = singletonManager.getCache(&#8220;testCache&#8221;); <br />删除只需要调用singletonManager.removeCache(&#8220;testCache&#8221;); <br />Shotdown CacheManager <br />在使用完Ehcache后，必须要shutdown缓存。Ehcache中有自己的关闭机制，不过最好在你的代码中显示调用CacheManager.getInstance().shutdown();</p>
<p>1.EhCache是什么<br />&nbsp;&nbsp;&nbsp; EhCache是Hibernate的二级缓存技术之一，可以把查询出来的数据存储在内存或者磁盘，节省下次同样查询语句再次查询数据库，大幅减轻数据库压力；</p>
<p>2.EhCache的使用注意点<br />&nbsp;&nbsp;&nbsp; 当用Hibernate的方式修改表数据(save,update,delete等等)，这时EhCache会自动把缓存中关于此表的所有缓存全部删除掉(这样能达到同步)。但对于数据经常修改的表来说，可能就失去缓存的意义了(不能减轻数据库压力)；</p>
<p>3.EhCache使用的场合<br />&nbsp;&nbsp;&nbsp; 3.1比较少更新表数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EhCache一般要使用在比较少执行write操作的表(包括update,insert,delete等)[Hibernate的二级缓存也都是这样]；<br />&nbsp;&nbsp;&nbsp; 3.2对并发要求不是很严格的情况<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 两台机子中的缓存是不能实时同步的；</p>
<p>4.在项目做的实现<br />&nbsp;&nbsp;&nbsp; 4.1在工程的src目录下添加ehcache.xml文件，内容如下：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ehcache&gt;&nbsp;&nbsp; 　<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;diskStore path="java.io.tmpdir" /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;defaultCache maxElementsInMemory="5"&lt;!--缓存可以存储的总记录量--&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal="false"&lt;!--缓存是否永远不销毁--&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflowToDisk="true"&lt;!--当缓存中的数据达到最大值时，是否把缓存数据写入磁盘--&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToIdleSeconds="15"&lt;!--当缓存闲置时间超过该值，则缓存自动销毁--&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToLiveSeconds="120"&lt;!--缓存创建之后，到达该缓存自动销毁--&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/ehcache&gt;<br />&nbsp;&nbsp;&nbsp; 4.2在Hibernate.cfg.xml中的mapping标签上面加以下内容：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="show_sql"&gt;true&lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="hibernate.cache.provider_class"&gt;org.hibernate.cache.EhCacheProvider&lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="hibernate.cache.use_query_cache"&gt;true&lt;/property&gt;<br />&nbsp;&nbsp;&nbsp; 4.3在要缓存的bean的hbm.xml文件中的class标签下加入以下内容：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;cache usage="read-only" /&gt;&lt;!--也可读写--&gt;<br />&nbsp;&nbsp;&nbsp; 4.4创建DAO，内容如下：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session s = HibernateSessionFactory.getSession();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Criteria c = s.createCriteria(Xyz.class);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.setCacheable(true);//这句必须要有<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("第一次读取");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List l = c.list();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(l.size());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HibernateSessionFactory.closeSession();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = HibernateSessionFactory.getSession();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c = s.createCriteria(Xyz.class);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.setCacheable(true);//这句必须要有<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("第二次读取");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l = c.list();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(l.size());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HibernateSessionFactory.closeSession();<br />&nbsp;&nbsp; 4.5这时你会看到打印出来的信息为（表示第二次并没有去读库）：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一次读取<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hibernate: *******<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 13<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二次读取<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 13</p>
<p>配置Spring+hibernate使用ehcache作为second-level cache</p>
<p>大量数据流动是web应用性能问题常见的原因，而缓存被广泛的用于优化数据库应用。cache被设计为通过保存从数据库里load的数据来减少应用和数据库之间的数据流动。数据库访问只有当检索的数据不在cache里可用时才必要。hibernate可以用两种不同的对象缓存：first-level cache 和 second-level cache。first-level cache和Session对象关联，而second-level cache是和Session Factory对象关联。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 缺省地，hibernate已经使用基于每个事务的first-level cache。 Hibernate用first-level cache主要是减少在一个事务内的sql查询数量。例如，如果一个对象在同一个事务内被修改多次，hibernate将只生成一个包括所有修改的 UPDATE SQL语句。为了减少数据流动，second-level cache在Session Factory级的不同事务之间保持load的对象，这些对象对整个应用可用，不只是对当前用户正在运行的查询。这样，每次查询将返回已经load在缓存里的对象，避免一个或更多潜在的数据库事务。</p>
<p>下载ehcache，hibernate3.2必须要ehcache1.2以上才能支持。可以修改log4j配置文件log4j.logger.net.sf.hibernate.cache=debug查看日志</p>
<p>1.在类路径上ehcache.xml：</p>
<p>&lt;ehcache&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- Sets the path to the directory where cache .data files are created.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If the path is a Java System Property it is replaced by<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; its value in the running VM.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The following properties are translated:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user.home - User's home directory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user.dir - User's current working directory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.tmpdir - Default temp file path --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp; &lt;diskStore path="java.io.tmpdir"/&gt;</p>
<p><br />&nbsp;&nbsp;&nbsp;&nbsp; &lt;!--Default Cache configuration. These will applied to caches programmatically created through<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the CacheManager.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The following attributes are required:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Sets the maximum number of objects that will be created in memory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Sets whether elements are eternal. If eternal,&nbsp;&nbsp; timeouts are ignored and the<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; element is never expired.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflowToDisk&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Sets whether elements can overflow to disk when the in-memory cache<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; has reached the maxInMemory limit.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The following attributes are optional:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToIdleSeconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Sets the time to idle for an element before it expires.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i.e. The maximum amount of time between accesses before an element expires<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Is only used if the element is not eternal.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Optional attribute. A value of 0 means that an Element can idle for infinity.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The default value is 0.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToLiveSeconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Sets the time to live for an element before it expires.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i.e. The maximum time between creation time and when an element expires.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Is only used if the element is not eternal.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Optional attribute. A value of 0 means that and Element can live for infinity.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The default value is 0.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; diskPersistent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Whether the disk store persists between restarts of the Virtual Machine.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The default value is false.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is 120 seconds.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;defaultCache<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory="10000"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal="false"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflowToDisk="true"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToIdleSeconds="120"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToLiveSeconds="120"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; diskPersistent="false"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; diskExpiryThreadIntervalSeconds="120"/&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- See <a href="http://ehcache.sourceforge.net/documentation/#mozTocId258426">http://ehcache.sourceforge.net/documentation/#mozTocId258426</a> for how to configure caching for your objects --&gt;<br />&lt;/ehcache&gt;</p>
<p>2.applicationContext-hibernate.xml里Hibernate SessionFactory配置：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- Hibernate SessionFactory --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="dataSource" ref="dataSource"/&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="configLocation"&gt;&lt;value&gt;classpath:hibernate.cfg.xml&lt;/value&gt;&lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- The property below is commented out b/c it doesn't work when run via<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ant in Eclipse.&nbsp;&nbsp; It works fine for individual JUnit tests and in IDEA ??<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="mappingJarLocations"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;&lt;value&gt;file:dist/appfuse-dao.jar&lt;/value&gt;&lt;/list&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="hibernateProperties"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;props&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.dialect"&gt;@HIBERNATE-DIALECT@&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!--&lt;prop key="hibernate.show_sql"&gt;true&lt;/prop&gt;--&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.max_fetch_depth"&gt;3&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.hibernate.use_outer_join"&gt;true&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.jdbc.batch_size"&gt;10&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.cache.use_query_cache"&gt;true&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.cache.use_second_level_cache"&gt;true&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.cache.provider_class"&gt;org.hibernate.cache.EhCacheProvider&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!--<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.use_sql_comments"&gt;false&lt;/prop&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- Create/update the database tables automatically when the JVM starts up<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.hbm2ddl.auto"&gt;update&lt;/prop&gt; --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- Turn batching off for better error messages under PostgreSQL<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;prop key="hibernate.jdbc.batch_size"&gt;0&lt;/prop&gt; --&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/props&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="entityInterceptor"&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref local="auditLogInterceptor"/&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />说明：如果不设置&#8220;查询缓存&#8221;，那么hibernate只会缓存使用load()方法获得的单个持久化对象，如果想缓存使用findall()、 list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话，就需要设置 hibernate.cache.use_query_cache true 才行</p>
<p>3.model类里采用Xdoclet生成*.hbm.xml里的cache xml标签，即&lt;cache usage="read-only"/&gt;</p>
<p>/**<br />* @hibernate.class table="WF_WORKITEM_HIS"<br />* @hibernate.cache usage="read-write"<br />* <br />*/</p>
<p><br />4.对于"query cache"，需要在程序里编码：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getHibernateTemplate().setCacheQueries(true);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getHibernateTemplate().find(hql);</p>
<p>使用spring和hibernate配置ehcache和query cache<br />1、applicationContext.xml<br />&lt;prop key="hibernate.cache.provider_class"&gt;org.hibernate.cache.EhCacheProvider&lt;/prop&gt;<br />&lt;prop key="hibernate.cache.use_query_cache"&gt;true&lt;/prop&gt; <br />这两句加到hibernateProperties中<br />&lt;bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"&gt;<br />&lt;property name="sessionFactory"&gt;<br />&nbsp;&nbsp; &lt;ref bean="sessionFactory" /&gt;<br />&lt;/property&gt;<br />&lt;property name="cacheQueries"&gt;<br />&nbsp;&nbsp; &lt;value&gt;true&lt;/value&gt;<br />&lt;/property&gt;<br />&lt;/bean&gt;</p>
<p>添加此bean到applicationcontext.xml中。在各个DAO的bean中，更改如下<br />&lt;property name="sessionFactory"&gt;<br />&lt;ref bean="sessionFactory" /&gt;<br />&lt;/property&gt;<br />改为<br />&lt;property name="hibernateTemplate"&gt;<br />&lt;ref bean="hibernateTemplate" /&gt;<br />&lt;/property&gt;</p>
<p>2、ehcache.xml文件放在classes根目录即可</p>
<p>3、pojo与ehcache.xml的配置关系<br />以com.ce.ceblog.pojos.CeblogJournal为例子<br />在CeblogJournal.hbm.xml中配置：<br />&lt;class name="CeblogJournal" table="CEBLOG_JOURNAL" lazy="false"&gt;<br />&lt;cache usage="read-write" region="ehcache.xml中的name的属性值"/&gt;<br />注意：这一句需要紧跟在class标签下面，其他位置无效。</p>
<p>Ehcache.xml文件主体如下<br />&lt;defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="1" timeToLiveSeconds="1" overflowToDisk="true" /&gt;<br />&lt;cache name="com.ce.ceblog.pojos.CeblogJournal" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /&gt;<br />hbm文件查找cache方法名的策略：如果不指定hbm文件中的region="ehcache.xml中的name的属性值"，则使用name名为 com.ce.ceblog.pojos.CeblogJournal的cache，如果不存在与类名匹配的cache名称，则用 defaultCache。<br />如果CeblogJournal包含set集合，则需要另行指定其cache<br />例如CeblogJournal包含ceblogReplySet集合，则需要<br />添加如下配置到ehcache.xml中<br />&lt;cache name="com.ce.ceblog.pojos.CeblogJournal.ceblogReplySet"<br />maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300"<br />timeToLiveSeconds="600" overflowToDisk="true" /&gt;</p>
<p>另，针对查询缓存的配置如下：<br />&lt;cache name="org.hibernate.cache.UpdateTimestampsCache"<br />maxElementsInMemory="5000"<br />eternal="true"<br />overflowToDisk="true"/&gt;<br />&lt;cache name="org.hibernate.cache.StandardQueryCache"<br />maxElementsInMemory="10000"<br />eternal="false"<br />timeToLiveSeconds="120"<br />overflowToDisk="true"/&gt;</p>
<p>4、选择缓存策略依据：<br />&lt;cache usage="transactional|read-write|nonstrict-read-write|read-only" /&gt;<br />ehcache不支持transactional，其他三种可以支持。<br />read- only：无需修改， 那么就可以对其进行只读 缓存，注意，在此策略下，如果直接修改数据库，即使能够看到前台显示效果，但是将对象修改至cache中会报error，cache不会发生作用。另：删 除记录会报错，因为不能在read-only模式的对象从cache中删除。<br />read-write：需要更新数据，那么使用读/写缓存 比较合适，前提：数据库不可以为serializable transaction isolation level（序列化事务隔离级别）<br />nonstrict-read-write：只偶尔需要更新数据（也就是说，两个事务同时更新同一记录的情况很不常见），也不需要十分严格的事务隔离，那么比较适合使用非严格读/写缓存策略。</p>
<p>5、调试时候使用log4j的log4j.logger.org.hibernate.cache=debug，更方便看到ehcache的操作过程，主要用于调试过程,实际应用发布时候，请注释掉，以免影响性能。</p>
<p>6、 使用ehcache，打印sql语句是正常的，因为query cache设置为true将会创建两个缓存区域：一个用于保存查询结果集 (org.hibernate.cache.StandardQueryCache)；另一个则用于保存最近查询的一系列表的时间戳(org.hibernate.cache.UpdateTimestampsCache)。请注意：在查询缓存中，它并不缓存结果集中所包含的实体的确切状态；它只缓存这些实体的标识符属性的值、以及各值类型的结果。需要将打印sql语句与最近的cache内容相比较，将不同之处修改到cache中，所以查询缓存通常会和二级缓存一起使用。</p><img src ="http://www.blogjava.net/hao446tian/aggbug/350930.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-05-24 16:20 <a href="http://www.blogjava.net/hao446tian/archive/2011/05/24/350930.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用 Spring 和 EHCache 做方法缓存处理〔转〕</title><link>http://www.blogjava.net/hao446tian/archive/2011/03/08/345923.html</link><dc:creator>昊天</dc:creator><author>昊天</author><pubDate>Tue, 08 Mar 2011 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/hao446tian/archive/2011/03/08/345923.html</guid><wfw:comment>http://www.blogjava.net/hao446tian/comments/345923.html</wfw:comment><comments>http://www.blogjava.net/hao446tian/archive/2011/03/08/345923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hao446tian/comments/commentRss/345923.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hao446tian/services/trackbacks/345923.html</trackback:ping><description><![CDATA[利用 Spring 和 EHCache 缓存结果（翻译）<br />
<br />
导言 <br />
<br />
&nbsp;&nbsp; 从 Spring 1.1.1 开始，EHCache 就作为一种通用缓存解决方案集成进 Spring。 <br />
我将示范拦截器的例子，它能把方法返回的结果缓存起来。<br />
&nbsp;&nbsp;利用 Spring IoC 配置 EHCache <br />
在 Spring 里配置 EHCache 很简单。你只需一个 ehcache.xml 文件，该文件用于配置 EHCache：<br />
&lt;ehcache&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!—设置缓存文件 .data 的创建路径。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果该路径是 Java 系统参数，当前虚拟机会重新赋值。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面的参数这样解释：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user.home &#8211; 用户主目录<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user.dir&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8211; 用户当前工作目录<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.io.tmpdir &#8211; 默认临时文件路径 --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;diskStore path="java.io.tmpdir"/&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!—缺省缓存配置。CacheManager 会把这些配置应用到程序中。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下列属性是 defaultCache 必须的：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxInMemory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 设定内存中创建对象的最大值。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eternal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- 设置元素（译注：内存中对象）是否永久驻留。如果是，将忽略超<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;时限制且元素永不消亡。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeToIdleSeconds&nbsp;&nbsp;- 设置某个元素消亡前的停顿时间。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;也就是在一个元素消亡之前，两次访问时间的最大时间间隔值。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这只能在元素不是永久驻留时有效（译注：如果对象永恒不灭，则<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置该属性也无用）。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果该值是 0 就意味着元素可以停顿无穷长的时间。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeToLiveSeconds - 为元素设置消亡前的生存时间。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也就是一个元素从构建到消亡的最大时间间隔值。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这只能在元素不是永久驻留时有效。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;overflowToDisk&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- 设置当内存中缓存达到 maxInMemory 限制时元素是否可写到磁盘<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;cache name="org.taha.cache.METHOD_CACHE"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxElementsInMemory="300"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eternal="false"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeToIdleSeconds="500"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeToLiveSeconds="500"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;overflowToDisk="true"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/&gt;<br />
&lt;/ehcache&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 拦截器将使用 &#8221;org.taha.cache.METHOD_CACHE&#8221; 区域缓存方法返回结果。下面利用 Spring IoC 让 bean 来访问这一区域。<br />
&lt;!-- ======================&nbsp;&nbsp; 缓存&nbsp;&nbsp; ======================= --&gt;<br />
&lt;bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;<br />
&nbsp;&nbsp;&lt;property name="configLocation"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;classpath:ehcache.xml&lt;/value&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id="methodCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;<br />
&nbsp;&nbsp;&lt;property name="cacheManager"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref local="cacheManager"/&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="cacheName"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;org.taha.cache.METHOD_CACHE&lt;/value&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 构建我们的 MethodCacheInterceptor 该拦截器实现org.aopalliance.intercept.MethodInterceptor接口。一旦运行起来(kicks-in)，它首先检查被拦截方法是否被配置为可缓存的。这将可选择性的配置想要缓存的 bean 方法。只要调用的方法配置为可缓存，拦截器将为该方法生成 cache key 并检查该方法返回的结果是否已缓存。如果已缓存，就返回缓存的结果，否则再次调用被拦截方法，并缓存结果供下次调用。<br />
org.taha.interceptor.MethodCacheInterceptor<br />
/*<br />
* Copyright 2002-2004 the original author or authors.<br />
*<br />
* Licensed under the Apache License, Version 2.0 (the "License");<br />
* you may not use this file except in compliance with the License.<br />
* You may obtain a copy of the License at<br />
*<br />
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank" rel="external">http://www.apache.org/licenses/LICENSE-2.0</a><br />
*<br />
* Unless required by applicable law or agreed to in writing, software<br />
* distributed under the License is distributed on an "AS IS" BASIS,<br />
* WITHOUT WARRANTIES or CONDITIONS OF ANY KIND, either express or implied.<br />
* See the License for the specific language governing permissions and<br />
* limitations under the License.<br />
*/<br />
package org.taha.interceptor;<br />
import java.io.Serializable;<br />
import org.aopalliance.intercept.MethodInterceptor;<br />
import org.aopalliance.intercept.MethodInvocation;<br />
import org.apache.commons.logging.LogFactory;<br />
import org.apache.commons.logging.Log;<br />
import org.springframework.beans.factory.InitializingBean;<br />
import org.springframework.util.Assert;<br />
import net.sf.ehcache.Cache;<br />
import net.sf.ehcache.Element;<br />
/**<br />
* @author &lt;a href="mailto:irbouh@gmail.com"&gt;Omar Irbouh&lt;/a&gt;<br />
* @since 2004.10.07<br />
*/<br />
public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean {<br />
&nbsp;&nbsp;private static final Log logger = LogFactory.getLog(MethodCacheInterceptor.class);<br />
&nbsp;&nbsp;private Cache cache;<br />
&nbsp;&nbsp;/**<br />
&nbsp;&nbsp; * 设置缓存名<br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;public void setCache(Cache cache) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;this.cache = cache;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;/**<br />
&nbsp;&nbsp; * 检查是否提供必要参数。<br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;public void afterPropertiesSet() throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one.");<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;/**<br />
&nbsp;&nbsp; * 主方法<br />
&nbsp;&nbsp; * 如果某方法可被缓存就缓存其结果<br />
&nbsp;&nbsp; * 方法结果必须是可序列化的(serializable)<br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;public Object invoke(MethodInvocation invocation) throws Throwable {<br />
&nbsp;&nbsp;&nbsp;&nbsp;String targetName&nbsp;&nbsp;= invocation.getThis().getClass().getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;String methodName&nbsp;&nbsp;= invocation.getMethod().getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Object[] arguments = invocation.getArguments();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Object result;<br />
&nbsp;&nbsp;&nbsp;&nbsp;logger.debug("looking for method result in cache");<br />
&nbsp;&nbsp;&nbsp;&nbsp;String cacheKey = getCacheKey(targetName, methodName, arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;Element element = cache.get(cacheKey);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (element == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//call target/sub-interceptor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug("calling intercepted method");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = invocation.proceed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//cache method result<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug("caching result");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;element = new Element(cacheKey, (Serializable) result);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache.put(element);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return element.getValue();<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;/**<br />
&nbsp;&nbsp; * creates cache key: targetName.methodName.argument0.argument1...<br />
&nbsp;&nbsp; */<br />
&nbsp;&nbsp;private String getCacheKey(String targetName,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String methodName,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object[] arguments) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer sb = new StringBuffer();<br />
&nbsp;&nbsp;&nbsp;&nbsp;sb.append(targetName)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.append(".").append(methodName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if ((arguments != null) &amp;&amp; (arguments.length != 0)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i=0; i&lt;arguments.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(".")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.append(arguments[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return sb.toString();<br />
&nbsp;&nbsp;}<br />
}<br />
<br />
<br />
<br />
<br />
MethodCacheInterceptor 代码说明了： <br />
&nbsp;&nbsp;&nbsp;&nbsp;默认条件下，所有方法返回结果都被缓存了（methodNames 是 null） <br />
&nbsp;&nbsp;&nbsp;&nbsp;缓存区利用 IoC 形成 <br />
&nbsp;&nbsp;&nbsp;&nbsp;cacheKey 的生成还包括方法参数的因素（译注：参数的改变会影响 cacheKey） <br />
使用 MethodCacheInterceptor <br />
下面摘录了怎样配置 MethodCacheInterceptor：<br />
&lt;bean id="methodCacheInterceptor" class="org.taha.interceptor.MethodCacheInterceptor"&gt;<br />
&nbsp;&nbsp;&lt;property name="cache"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref local="methodCache" /&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&gt;<br />
&nbsp;&nbsp;&lt;property name="advice"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;ref local="methodCacheInterceptor"/&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="patterns"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;.*methodOne&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;.*methodTwo&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id="myBean" class="org.springframework.aop.framework.ProxyFactoryBean"&gt;<br />
&nbsp;&nbsp;&lt;property name="target"&gt;<br />
&nbsp;&nbsp; &lt;bean class="org.taha.beans.MyBean"/&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="interceptorNames"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;methodCachePointCut&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&lt;/bean&gt;<br />
 <img src ="http://www.blogjava.net/hao446tian/aggbug/345923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hao446tian/" target="_blank">昊天</a> 2011-03-08 11:25 <a href="http://www.blogjava.net/hao446tian/archive/2011/03/08/345923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>