﻿<?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-ljf2999-文章分类-S.S.Hibernate</title><link>http://www.blogjava.net/ljf2999/category/17899.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 19 Jun 2007 05:39:48 GMT</lastBuildDate><pubDate>Tue, 19 Jun 2007 05:39:48 GMT</pubDate><ttl>60</ttl><item><title>转:hibernate二级缓存攻略 </title><link>http://www.blogjava.net/ljf2999/articles/125091.html</link><dc:creator>ljf2999</dc:creator><author>ljf2999</author><pubDate>Tue, 19 Jun 2007 04:17:00 GMT</pubDate><guid>http://www.blogjava.net/ljf2999/articles/125091.html</guid><wfw:comment>http://www.blogjava.net/ljf2999/comments/125091.html</wfw:comment><comments>http://www.blogjava.net/ljf2999/articles/125091.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljf2999/comments/commentRss/125091.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljf2999/services/trackbacks/125091.html</trackback:ping><description><![CDATA[<h2>很多人对二级缓存都不太了解，或者是有错误的认识，我一直想写一篇文章介绍一下hibernate的二级缓存的，今天终于忍不住了。 <br>我的经验主要来自hibernate2.1版本，基本原理和3.0、3.1是一样的，请原谅我的顽固不化。</h2>
<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/ljf2999/aggbug/125091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljf2999/" target="_blank">ljf2999</a> 2007-06-19 12:17 <a href="http://www.blogjava.net/ljf2999/articles/125091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转:Hibernate程序性能优化的考虑要点 </title><link>http://www.blogjava.net/ljf2999/articles/125089.html</link><dc:creator>ljf2999</dc:creator><author>ljf2999</author><pubDate>Tue, 19 Jun 2007 04:15:00 GMT</pubDate><guid>http://www.blogjava.net/ljf2999/articles/125089.html</guid><wfw:comment>http://www.blogjava.net/ljf2999/comments/125089.html</wfw:comment><comments>http://www.blogjava.net/ljf2999/articles/125089.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljf2999/comments/commentRss/125089.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljf2999/services/trackbacks/125089.html</trackback:ping><description><![CDATA[本文依照HIBERNATE帮助文档，一些网络书籍及项目经验整理而成，只提供要点和思路，具体做法可以留言探讨，或是找一些更详细更有针对性的资料。<br><br>
<p>　　初用HIBERNATE的人也许都遇到过性能问题，实现同一功能，用HIBERNATE与用JDBC性能相差十几倍很正常，如果不及早调整，很可能影响整个项目的进度。</p>
<p>　　大体上，对于HIBERNATE性能调优的主要考虑点如下:</p>
<p>　　&#216; 数据库设计调整</p>
<p>　　&#216; HQL优化</p>
<p>　　&#216; API的正确使用(如根据不同的业务类型选用不同的集合及查询API)</p>
<p>　　&#216; 主配置参数(日志，查询缓存，fetch_size, batch_size等)</p>
<p>　　&#216; 映射文件优化(ID生成策略，二级缓存，延迟加载，关联优化)</p>
<p>　　&#216; 一级缓存的管理</p>
<p>　　&#216; 针对二级缓存，还有许多特有的策略</p>
<p>　　&#216; 事务控制策略。</p>
<p><strong>　　1、 数据库设计</strong></p>
<p>　　a) 降低关联的复杂性</p>
<p>　　b) 尽量不使用联合主键</p>
<p>　　c) ID的生成机制，不同的数据库所提供的机制并不完全一样</p>
<p>　　d) 适当的冗余数据，不过分追求高范式</p>
<p><strong>　　2、 HQL优化</strong></p>
<p>　　HQL如果抛开它同HIBERNATE本身一些缓存机制的关联，HQL的优化技巧同普通的SQL优化技巧一样，可以很容易在网上找到一些经验之谈。</p>
<p><strong>　　3、 主配置</strong></p>
<p>　　a) 查询缓存，同下面讲的缓存不太一样，它是针对HQL语句的缓存，即完全一样的语句再次执行时可以利用缓存数据。但是，查询缓存在一个交易系统(数据变更频繁，查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却难以派上用场。</p>
<p>　　b) fetch_size，同JDBC的相关参数作用类似，参数并不是越大越好，而应根据业务特征去设置</p>
<p>　　c) batch_size同上。</p>
<p>　　d) 生产系统中，切记要关掉SQL语句打印。</p>
<p><strong>　　4、 缓存</strong></p>
<p>　　a) 数据库级缓存:这级缓存是最高效和安全的，但不同的数据库可管理的层次并不一样，比如，在ORACLE中，可以在建表时指定将整个表置于缓存当中。</p>
<p>　　b) SESSION缓存:在一个HIBERNATE SESSION有效，这级缓存的可干预性不强，大多于HIBERNATE自动管理，但它提供清除缓存的方法，这在大批量增加/更新操作是有效的。比如，同时增加十万条记录，按常规方式进行，很可能会发现OutofMemeroy的异常，这时可能需要手动清除这一级缓存:Session.evict以及Session.clear</p>
<p>　　c) 应用缓存:在一个SESSIONFACTORY中有效，因此也是优化的重中之重，因此，各类策略也考虑的较多，在将数据放入这一级缓存之前，需要考虑一些前提条件:</p>
<p>　　i. 数据不会被第三方修改(比如，是否有另一个应用也在修改这些数据?)</p>
<p>　　ii. 数据不会太大</p>
<p>　　iii. 数据不会频繁更新(否则使用CACHE可能适得其反)</p>
<p>　　iv. 数据会被频繁查询</p>
<p>　　v. 数据不是关键数据(如涉及钱，安全等方面的问题)。</p>
<p>　　缓存有几种形式，可以在映射文件中配置:read-only(只读，适用于很少变更的静态数据/历史数据)，nonstrict-read-write，read-write(比较普遍的形式，效率一般)，transactional(JTA中，且支持的缓存产品较少)</p>
<p>　　d) 分布式缓存:同c)的配置一样，只是缓存产品的选用不同，在目前的HIBERNATE中可供选择的不多，oscache, jboss cache，目前的大多数项目，对它们的用于集群的使用(特别是关键交易系统)都持保守态度。在集群环境中，只利用数据库级的缓存是最安全的。</p>
<p><strong>　　5、 延迟加载</strong></p>
<p>　　a) 实体延迟加载:通过使用动态代理实现</p>
<p>　　b) 集合延迟加载:通过实现自有的SET/LIST，HIBERNATE提供了这方面的支持</p>
<p>　　c) 属性延迟加载:</p>
<p><strong>　　6、 方法选用</strong></p>
<p>　　a) 完成同样一件事，HIBERNATE提供了可供选择的一些方式，但具体使用什么方式，可能用性能/代码都会有影响。显示，一次返回十万条记录(List/Set/Bag/Map等)进行处理，很可能导致内存不够的问题，而如果用基于游标(ScrollableResults)或Iterator的结果集，则不存在这样的问题。</p>
<p>　　b) Session的load/get方法，前者会使用二级缓存，而后者则不使用。</p>
<p>　　c) Query和list/iterator，如果去仔细研究一下它们，你可能会发现很多有意思的情况，二者主要区别(如果使用了Spring，在HibernateTemplate中对应find,iterator方法):</p>
<p>　　i. list只能利用查询缓存(但在交易系统中查询缓存作用不大)，无法利用二级缓存中的单个实体，但list查出的对象会写入二级缓存，但它一般只生成较少的执行SQL语句，很多情况就是一条(无关联)。</p>
<p>　　ii. iterator则可以利用二级缓存，对于一条查询语句，它会先从数据库中找出所有符合条件的记录的ID，再通过ID去缓存找，对于缓存中没有的记录，再构造语句从数据库中查出，因此很容易知道，如果缓存中没有任何符合条件的记录，使用iterator会产生N+1条SQL语句(N为符合条件的记录数)</p>
<p>　　iii. 通过iterator，配合缓存管理API，在海量数据查询中可以很好的解决内存问题，如:</p>
<p>　　while(it.hasNext()){</p>
<p>　　YouObject object = (YouObject)it.next();</p>
<p>　　session.evict(youObject);</p>
<p>　　sessionFactory.evice(YouObject.class, youObject.getId());</p>
<p>　　}</p>
<p>　　如果用list方法，很可能就出OutofMemory错误了。</p>
<p>　　iv. 通过上面的说明，我想你应该知道如何去使用这两个方法了。</p>
<p><strong>　　7、 集合的选用</strong></p>
<p>　　在HIBERNATE 3.1文档的&#8220;19.5. Understanding Collection performance&#8221;中有详细的说明。</p>
<p><strong>　　8、 事务控制</strong></p>
<p>　　事务方面对性能有影响的主要包括:事务方式的选用，事务隔离级别以及锁的选用</p>
<p>　　a) 事务方式选用:如果不涉及多个事务管理器事务的话，不需要使用JTA，只有JDBC的事务控制就可以。</p>
<p>　　b) 事务隔离级别:参见标准的SQL事务隔离级别</p>
<p>　　c) 锁的选用:悲观锁(一般由具体的事务管理器实现)，对于长事务效率低，但安全。乐观锁(一般在应用级别实现)，如在HIBERNATE中可以定义VERSION字段，显然，如果有多个应用操作数据，且这些应用不是用同一种乐观锁机制，则乐观锁会失效。因此，针对不同的数据应有不同的策略，同前面许多情况一样，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解。</p>
<p><strong>　　9、 批量操作</strong></p>
<p>　　即使是使用JDBC，在进行大批数据更新时，BATCH与不使用BATCH有效率上也有很大的差别。我们可以通过设置batch_size来让其支持批量操作。</p>
<p>　　举个例子，要批量删除某表中的对象，如&#8220;delete Account&#8221;，打出来的语句，会发现HIBERNATE找出了所有ACCOUNT的ID，再进行删除，这主要是为了维护二级缓存，这样效率肯定高不了，在后续的版本中增加了bulk delete/update，但这也无法解决缓存的维护问题。也就是说，由于有了二级缓存的维护问题，HIBERNATE的批量操作效率并不尽如人意!</p>
<p>　　从前面许多要点可以看出，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解，一般的，优化方案应在架构设计期就基本确定，否则可能导致没必要的返工，致使项目延期，而作为架构师和项目经理，还要面对开发人员可能的抱怨，必竟，我们对用户需求更改的控制力不大，但技术/架构风险是应该在初期意识到并制定好相关的对策。</p>
<p>　　还有一点要注意，应用层的缓存只是锦上添花，永远不要把它当救命稻草，应用的根基(数据库设计，算法，高效的操作语句，恰当API的选择等)才是最重要的。</p>
<img src ="http://www.blogjava.net/ljf2999/aggbug/125089.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljf2999/" target="_blank">ljf2999</a> 2007-06-19 12:15 <a href="http://www.blogjava.net/ljf2999/articles/125089.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转:Hibernate获取数据方式与缓存使用 </title><link>http://www.blogjava.net/ljf2999/articles/125090.html</link><dc:creator>ljf2999</dc:creator><author>ljf2999</author><pubDate>Tue, 19 Jun 2007 04:15:00 GMT</pubDate><guid>http://www.blogjava.net/ljf2999/articles/125090.html</guid><wfw:comment>http://www.blogjava.net/ljf2999/comments/125090.html</wfw:comment><comments>http://www.blogjava.net/ljf2999/articles/125090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljf2999/comments/commentRss/125090.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljf2999/services/trackbacks/125090.html</trackback:ping><description><![CDATA[<h2>Hibernate获取数据的方式有不同的几种，其与缓存结合使用的效果也不尽相同，而Hibernate中具体怎么使用缓存其实是我们很关心的一个问题，直接涉及到性能方面。<br>缓存在Hibernate中主要有三个方面：一级缓存、二级缓存和查询缓存；一级缓存在Hibernate中对应的即为session范围的缓存，也就是当session关闭时缓存即被清除，一级缓存在Hibernate中是不可配置的部分；二级缓存在Hibernate中对应的即为SessionFactory范围的缓存，通常来讲SessionFactory的生命周期和应用的生命周期相同，所以可以看成是进程缓存或集群缓存，二级缓存在Hibernate中是可以配置的，可以通过class-cache配置类粒度级别的缓存(class-cache在class中数据发生任何变化的情况下自动更新)，同时也可通过collection-cache配置集合粒度级别的缓存(collection-cache仅在collection中增加了元素或者删除了元素的情况下才自动更新，也就是当collection中元素发生值的变化的情况下它是不会自动更新的)，缓存自然会带来并发的访问问题，这个时候相应的就要根据应用来设置缓存所采用的事务隔离级别，和数据库的事务隔离级别概念基本一样，没什么多介绍的，^_^；查询缓存在Hibernate同样是可配置的，默认是关闭的，可以通过设置cache.use_&nbsp;query_cache为true来打开查询缓存。根据缓存的通常实现策略，我们可以来理解Hibernate的这三种缓存，缓存的实现通过是通过key/value的Map方式来实现，在Hibernate的一级、二级和查询缓存也同样如此，一级、二级缓存使用的key均为po的主键ID，value即为po实例对象，查询缓存使用的则为查询的条件、查询的参数、查询的页数，value有两种情况，如果采用的是select po.property这样的方式那么value为整个结果集，如采用的是from这样的方式那么value为获取的结果集中各po对象的主键ID，这样的作用很明显，节省内存，^_^<br>简单介绍完Hibernate的缓存后，再结合Hibernate的获取数据方式来说明缓存的具体使用方式，在Hibernate中获取数据常用的方式主要有四种：Session.load、Session.get、Query.list、Query.iterator。<br>1、Session.load<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在执行session.load时，Hibernate首先从当前session的一级缓存中获取id对应的值，在获取不到的情况下，将根据该对象是否配置了二级缓存来做相应的处理，如配置了二级缓存，则从二级缓存中获取id对应的值，如仍然获取不到则还需要根据是否配置了延迟加载来决定如何执行，如未配置延迟加载则从数据库中直接获取，在从数据库获取到数据的情况下，Hibernate会相应的填充一级缓存和二级缓存，如配置了延迟加载则直接返回一个代理类，只有在触发代理类的调用时才进行数据库查询的操作。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这样的情况下我们就可以看到，在session一直打开的情况下，要注意在适当的时候对一级缓存进行刷新操作，通常是在该对象具有单向关联维护的时候，在Hibernate中可以使用象session.clear、session.evict的方式来强制刷新一级缓存。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二级缓存则在数据发生任何变化(新增、更新、删除)的情况下都会自动的被更新。<br>2、Session.get<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在执行Session.get时，和Session.load不同的就是在当从缓存中获取不到时，直接从数据库中获取id对应的值。<br>3、Query.list<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在执行Query.list时，Hibernate的做法是首先检查是否配置了查询缓存，如配置了则从查询缓存中查找key为查询语句+查询参数+分页条件的值，如获取不到则从数据库中进行获取，从数据库获取到后Hibernate将会相应的填充一级、二级和查询缓存，如获取到的为直接的结果集，则直接返回，如获取到的为一堆id的值，则再根据id获取相应的值(Session.load)，最后形成结果集返回，可以看到，在这样的情况下，list也是有可能造成N次的查询的。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 查询缓存在数据发生任何变化的情况下都会被自动的清空。<br>4、Query.iterator<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在执行Query.iterator时，和Query.list的不同的在于从数据库获取的处理上，Query.iterator向数据库发起的是select id from这样的语句，也就是它是先获取符合查询条件的id，之后在进行iterator.next调用时才再次发起session.load的调用获取实际的数据。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可见，在拥有二级缓存并且查询参数多变的情况下，Query.iterator会比Query.list更为高效。<br><br>这四种获取数据的方式都各有适用的场合，要根据实际情况做相应的决定，^_^，最好的方式无疑就是打开show_sql选项看看执行的情况来做分析，系统结构上只用保证这种调整是容易实现的就好了，在cache这个方面的调整自然是非常的容易，只需要调整配置文件里的设置，而查询的方式则可对外部进行屏蔽，这样要根据实际情况调整也非常容易。<br><br>推荐三篇关于Hibernate缓存机制介绍的文章：<br><a href="http://gocom.primeton.com/blog/index.php?op=ViewArticle&amp;articleId=467&amp;blogId=37&amp;src=jdon&amp;srcforum=62"><font color=#0000ff>http://gocom.primeton.com/blog/index.php?op=ViewArticle&amp;articleId=467&amp;blogId=37&amp;src=jdon&amp;srcforum=62</font></a><br><a href="http://club.gamvan.com/club/clubPage.jsp?ccStyle=0&amp;tID=10456&amp;ccID=37"><font color=#0000ff>http://club.gamvan.com/club/clubPage.jsp?ccStyle=0&amp;tID=10456&amp;ccID=37</font></a><br><a href="http://www.devx.com/dbzone/Article/29685/1954?pf=true"><font color=#0000ff>http://www.devx.com/dbzone/Article/29685/1954?pf=true</font></a></h2>
<img src ="http://www.blogjava.net/ljf2999/aggbug/125090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljf2999/" target="_blank">ljf2999</a> 2007-06-19 12:15 <a href="http://www.blogjava.net/ljf2999/articles/125090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate test</title><link>http://www.blogjava.net/ljf2999/articles/59586.html</link><dc:creator>ljf2999</dc:creator><author>ljf2999</author><pubDate>Sat, 22 Jul 2006 14:14:00 GMT</pubDate><guid>http://www.blogjava.net/ljf2999/articles/59586.html</guid><wfw:comment>http://www.blogjava.net/ljf2999/comments/59586.html</wfw:comment><comments>http://www.blogjava.net/ljf2999/articles/59586.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljf2999/comments/commentRss/59586.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljf2999/services/trackbacks/59586.html</trackback:ping><description><![CDATA[
		<p> </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">package</span>
				<span style="COLOR: #000000"> cn.com.chengang.sms.db;<br /></span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> java.util.List;<br /></span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> net.sf.hibernate.HibernateException;<br /></span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> net.sf.hibernate.Query;<br /></span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> net.sf.hibernate.Session;<br /></span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> net.sf.hibernate.Transaction;<br /></span>
				<span style="COLOR: #008080"> 9</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> cn.com.chengang.sms.model.Grade;<br /></span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_270_1050_Open_Image" onclick="this.style.display='none'; Codehighlighter1_270_1050_Open_Text.style.display='none'; Codehighlighter1_270_1050_Closed_Image.style.display='inline'; Codehighlighter1_270_1050_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_270_1050_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_270_1050_Closed_Text.style.display='none'; Codehighlighter1_270_1050_Open_Image.style.display='inline'; Codehighlighter1_270_1050_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> HibernateTest </span>
				<span id="Codehighlighter1_270_1050_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_270_1050_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">12</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">13</span>
						<span style="COLOR: #000000">
								<img id="Codehighlighter1_326_595_Open_Image" onclick="this.style.display='none'; Codehighlighter1_326_595_Open_Text.style.display='none'; Codehighlighter1_326_595_Closed_Image.style.display='inline'; Codehighlighter1_326_595_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_326_595_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_326_595_Closed_Text.style.display='none'; Codehighlighter1_326_595_Open_Image.style.display='inline'; Codehighlighter1_326_595_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> insertGrade() </span>
						<span style="COLOR: #0000ff">throws</span>
						<span style="COLOR: #000000"> HibernateException </span>
						<span id="Codehighlighter1_326_595_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_326_595_Open_Text">
								<span style="COLOR: #000000">{<br /></span>
								<span style="COLOR: #008080">14</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Session session </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> HibernateUtil.currentSession();<br /></span>
								<span style="COLOR: #008080">15</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Transaction tx </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> session.beginTransaction();<br /></span>
								<span style="COLOR: #008080">16</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span>
								<span style="COLOR: #008080">17</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Grade grade </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> Grade();</span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">生成一个年级对象</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">18</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        grade.setName(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">高四</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">19</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span>
								<span style="COLOR: #008080">20</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        session.save(grade); </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">将这个对象保存到数据库</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">21</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        tx.commit();</span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">提交</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">22</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        HibernateUtil.closeSession();</span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">关闭session</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">23</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />
								</span>
								<span style="COLOR: #000000">    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">24</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
						</span>
						<span style="COLOR: #008080">25</span>
						<span style="COLOR: #000000">
								<img id="Codehighlighter1_649_1048_Open_Image" onclick="this.style.display='none'; Codehighlighter1_649_1048_Open_Text.style.display='none'; Codehighlighter1_649_1048_Closed_Image.style.display='inline'; Codehighlighter1_649_1048_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_649_1048_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_649_1048_Closed_Text.style.display='none'; Codehighlighter1_649_1048_Open_Image.style.display='inline'; Codehighlighter1_649_1048_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> List getGrades() </span>
						<span style="COLOR: #0000ff">throws</span>
						<span style="COLOR: #000000"> HibernateException </span>
						<span id="Codehighlighter1_649_1048_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_649_1048_Open_Text">
								<span style="COLOR: #000000">{<br /></span>
								<span style="COLOR: #008080">26</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Session session </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> HibernateUtil.currentSession();<br /></span>
								<span style="COLOR: #008080">27</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Transaction tx </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> session.beginTransaction();<br /></span>
								<span style="COLOR: #008080">28</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										<br />
								</span>
								<span style="COLOR: #008080">29</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">创建一个条件查询语句</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">30</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        String sql</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">select g from Grade as g where g.id &gt; :id</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">;<br /></span>
								<span style="COLOR: #008080">31</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Query query </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> session.createQuery(sql); </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">创建查询对象</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">32</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        query.setInteger(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">id</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">, </span>
								<span style="COLOR: #000000">2</span>
								<span style="COLOR: #000000">); </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">设置查询参数</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">33</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        List list </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> query.list(); </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">从数据库取出数据，并自动封装到List集合中</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">34</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        <br /></span>
								<span style="COLOR: #008080">35</span>
								<span style="COLOR: #000000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        tx.commit();</span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">提交</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">36</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        HibernateUtil.closeSession();</span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">关闭</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">37</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> list; </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">返回数据集</span>
								<span style="COLOR: #008000">
										<br />
								</span>
								<span style="COLOR: #008080">38</span>
								<span style="COLOR: #008000">
										<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />
								</span>
								<span style="COLOR: #000000">    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">39</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">40</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
<img src ="http://www.blogjava.net/ljf2999/aggbug/59586.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljf2999/" target="_blank">ljf2999</a> 2006-07-22 22:14 <a href="http://www.blogjava.net/ljf2999/articles/59586.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>