﻿<?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-我的地盘我作主-文章分类-Hibernate</title><link>http://www.blogjava.net/leedo/category/8813.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 15:10:48 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 15:10:48 GMT</pubDate><ttl>60</ttl><item><title>Criteria 查询表达式</title><link>http://www.blogjava.net/leedo/articles/78295.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Tue, 31 Oct 2006 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/78295.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/78295.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/78295.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/78295.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/78295.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Criteria 查询表达式 				                                       				 				 Criteria Query Criteria Query通过面向对象化的设计，将数据查询条件封装为一个对象。简单来讲，Criteria Query可以看作是传统SQL的对象化表示，如：Criteria criteria = session.createC...&nbsp;&nbsp;<a href='http://www.blogjava.net/leedo/articles/78295.html'>阅读全文</a><img src ="http://www.blogjava.net/leedo/aggbug/78295.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-10-31 15:42 <a href="http://www.blogjava.net/leedo/articles/78295.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>nhibernate架构分析(uml图) 茶秀网摘</title><link>http://www.blogjava.net/leedo/articles/38418.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Fri, 31 Mar 2006 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/38418.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/38418.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/38418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/38418.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/38418.html</trackback:ping><description><![CDATA[
		<table bgcolor="#ffffcc" border="0" cellpadding="0" cellspacing="1" width="100%">
				<tbody>
						<tr>
								<td bgcolor="#ffcc99" height="24" width="50%">nhibernate架构分析(uml图) 
		   
		  </td>
						</tr>
						<tr>
								<td colspan="3">
		
		  作者： billy_zh   <strong><font color="#575757">www.ASPCool.com</font></strong> 时间:2004-8-19 下午 01:47:20  阅读次数:<strong>8700</strong><br /></td>
						</tr>
						<tr>
								<td colspan="3" width="100%">
										<br />     <img src="http://blog.csdn.net/images/blog_csdn_net/billy_zh/19183/o_nhibernate-uml.jpg" /><br />  [以nhibernate-PreAlpha-Build-2为准]
<br />  
<br />  从图中可以看到，Session和SessionFactory是NHibernate的核心部分。
<br />  
<br />  SessionFactory维护到持久机制(数据库)的连接并对它们进行管理，同时还保存着所有持久对象的映射信息。
<br />  SessionFactory由Configuration.BuildSessionFactory创建，这个对象一般使用Singleton模式。
<br />  
<br />  Session用于将对象持久化，支持数据库事务，另外Session还提供了强大的数据加载功能。
<br />  Session由SessionFactory创建。
<br />  
<br />  其它对象说明:
<br />  IConnectionProvider: 连接提供者接口，负责与数据进行连接；
<br />  Dialect: 数据库方言；
<br />  CollectionPersister: 集合持久化类；
<br />  IClassPersister: 类持久化接口，定义了基本的CRUD操作；
<br />  TransactionFactory: 数据库事务工厂；
<br />  IInterceptor: 拦截器接口，用于在操作执行时进行一些处理，典型的就是记录操作日志；
</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/leedo/aggbug/38418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-03-31 10:53 <a href="http://www.blogjava.net/leedo/articles/38418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Speed Up Your Hibernate Applications with Second-Level Caching</title><link>http://www.blogjava.net/leedo/articles/37004.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Thu, 23 Mar 2006 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/37004.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/37004.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/37004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/37004.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/37004.html</trackback:ping><description><![CDATA[
		<table border="0" cellpadding="0" cellspacing="0">
				<tbody>
						<tr>
								<td>
										<div class="articleTitle">Speed Up Your Hibernate Applications with Second-Level Caching<br /><br />
http://www.devx.com/dbzone/Article/29685/1954?pf=true<br /></div>
										<div class="articleDek">
												<br />Newer
Hibernate developers sometimes don't understand Hibernate caching and
use it poorly as a result. However, when used correctly, it can be one
of the most powerful ways to accelerate Hibernate applications. <div><div class="articleAuthor">
						
							by
							John Ferguson Smart
						
						
						
						
						</div></div></div>
								</td>
						</tr>
						<tr>
								<td>
										<img src="http://assets.devx.com/dropcaps/3577.gif" />igh-volume
database traffic is a frequent cause of performance problems in Web
applications. Hibernate is a high-performance, object/relational
persistence and query service, but it won't solve all your performance
issues without a little help. In many cases, second-level caching can
be just what Hibernate needs to realize its full performance-handling
potential. This article examines Hibernate's caching functionalities
and shows how you can use them to significantly boost application
performance.
<p></p><h4>An Introduction to Caching</h4>Caching is widely used for
optimizing database applications. A cache is designed to reduce traffic
between your application and the database by conserving data already
loaded from the database. Database access is necessary only when
retrieving data that is not currently available in the cache. The
application may need to empty (invalidate) the cache from time to time
if the database is updated or modified in some way, because it has no
way of knowing whether the cache is up to date.
<p></p><h4>Hibernate Caching</h4>Hibernate uses two different caches for
objects: first-level cache and second-level cache. First-level cache is
associated with the Session object, while second-level cache is
associated with the Session Factory object. By default, Hibernate uses
first-level cache on a per-transaction basis. Hibernate uses this cache
mainly to reduce the number of SQL queries it needs to generate within
a given transaction. For example, if an object is modified several
times within the same transaction, Hibernate will generate only one SQL
UPDATE statement at the end of the transaction, containing all the
modifications.
This article focuses on second-level cache. To reduce database traffic,
second-level cache keeps loaded objects at the Session Factory level
between transactions. These objects are available to the whole
application, not just to the user running the query. This way, each
time a query returns an object that is already loaded in the cache, one
or more database transactions potentially are avoided.
<p>
In addition, you can use a query-level cache if you need to cache actual query results, rather than just persistent objects.
</p><p></p><h5>Cache Implementations</h5>Caches are complicated pieces of
software, and the market offers quite a number of choices, both open
source and commercial. Hibernate supports the following open-source
cache implementations out-of-the-box:
<ul><li><b>EHCache</b> (org.hibernate.cache.EhCacheProvider)</li><li><b>OSCache</b> (org.hibernate.cache.OSCacheProvider)</li><li><b>SwarmCache</b> (org.hibernate.cache.SwarmCacheProvider)</li><li><b>JBoss TreeCache</b> (org.hibernate.cache.TreeCacheProvider)</li></ul><p>
Each cache provides different capacities in terms of performance, memory use, and configuration possibilities:
</p><ul><li><a href="http://ehcache.sourceforge.net/" target="new">EHCache</a>
is a fast, lightweight, and easy-to-use in-process cache. It supports
read-only and read/write caching, and memory- and disk-based caching.
However, it does not support clustering.</li><li><a href="http://www.opensymphony.com/oscache/" target="new">OSCache</a>
is another open-source caching solution. It is part of a larger
package, which also provides caching functionalities for JSP pages or
arbitrary objects. It is a powerful and flexible package, which, like
EHCache, supports read-only and read/write caching, and memory- and
disk-based caching. It also provides basic support for clustering via
either JavaGroups or JMS.</li><li><a href="http://swarmcache.sourceforge.net/" target="new">SwarmCache</a>
is a simple cluster-based caching solution based on JavaGroups. It
supports read-only or nonstrict read/write caching (the next section
explains this term). This type of cache is appropriate for applications
that typically have many more read operations than write operations.</li><li><a href="http://www.jboss.com/products/jbosscache" target="new">JBoss TreeCache</a>
is a powerful replicated (synchronous or asynchronous) and
transactional cache. Use this solution if you really need a true
transaction-capable caching architecture.</li></ul><p>
Another cache implementation worth mentioning is the commercial <a href="http://hibernate.org/132.html" target="new">Tangosol Coherence cache</a>.
</p><p></p><h5>Caching Strategies</h5>
Once you have chosen your cache implementation, you need to specify
your access strategies. The following four caching strategies are
available:
<ul><li>Read-only: This strategy is useful for data that is read frequently
but never updated. This is by far the simplest and best-performing
cache strategy.</li><li>Read/write: Read/write caches may be appropriate if your data needs
to be updated. They carry more overhead than read-only caches. In
non-JTA environments, each transaction should be completed when
Session.close() or Session.disconnect() is called.</li><li>Nonstrict read/write: This strategy does not guarantee that two
transactions won't simultaneously modify the same data. Therefore, it
may be most appropriate for data that is read often but only
occasionally modified.</li><li>Transactional: This is a fully transactional cache that may be used only in a JTA environment.</li></ul><p>
Support for these strategies is not identical for every cache
implementation. Table 1 shows the options available for the different
cache implementations.
</p><p></p><table border="1" cellpadding="2" cellspacing="2"><tbody><tr><th>Cache</th><th>Read-only</th><th>Nonstrict Read/write</th><th>Read/write</th><th>Transactional</th></tr><tr><td>EHCache</td><td align="center">Yes</td><td align="center">Yes</td><td align="center">Yes</td><td align="center">No</td></tr><tr><td>OSCache</td><td align="center">Yes</td><td align="center">Yes</td><td align="center">Yes</td><td align="center">No</td></tr><tr><td>SwarmCache</td><td align="center">Yes</td><td align="center">Yes</td><td align="center">No</td><td align="center">No</td></tr><tr><td>JBoss TreeCache</td><td align="center">Yes</td><td align="center">No</td><td align="center">No</td><td align="center">Yes</td></tr></tbody></table><table><tbody><tr><td class="smallfont"><b>Table 1</b>. Supported Caching Strategies for Hibernate Out-of-the-Box Cache Implementations</td></tr></tbody></table><p> 
The remainder of the article demonstrates single-JVM caching using EHCache.
</p><p><br /><br /></p></td>
						</tr>
				</tbody>
		</table>
		<table border="0" cellpadding="0" cellspacing="0">
				<tbody>
						<tr>
								<td>
										<br />
								</td>
						</tr>
						<tr>
								<td>
										<h4>Cache Configuration</h4>To
activate second-level caching, you need to define the
hibernate.cache.provider_class property in the hibernate.cfg.xml file
as follows:
<pre><code><br />&lt;hibernate-configuration&gt;<br />	&lt;session-factory&gt;<br />		...<br />		&lt;property name="hibernate.cache.provider_class"&gt;<br />			org.hibernate.cache.EHCacheProvider<br />		&lt;/property&gt;<br />		...<br />	&lt;/session-factory&gt;<br />&lt;/hibernate-configuration&gt;<br /></code></pre><p>For testing purposes in Hibernate 3, you may also want to use the
hibernate.cache.use_second_level_cache property, which allows you to
activate (and deactivate) the second-level cache. By default, the
second-level cache is activated and uses the EHCache provider.
</p><p></p><h5>A Practical Application</h5><p></p><table align="right" border="0" cellpadding="5" cellspacing="0" width="175"><tbody><tr><td valign="top"><a href="javascript:showSupportItem('figure1');"><img alt="" src="http://assets.devx.com/articlefigs/14240.gif" border="0" height="165" width="175" /></a></td><td width="12"> </td></tr><tr><td class="smallfont"><a href="javascript:showSupportItem('figure1');">Figure 1</a>. The Employee UML Class Diagram</td></tr></tbody></table><p>The sample demo application for this article contains four
simple tables: a list of countries, a list of airports, a list of
employees, and a list of spoken languages. Each employee is assigned a
country, and can speak many languages. Each country can have any number
of airports. <a href="javascript:showSupportItem('figure1');">Figure 1</a> shows the UML class diagram for the application, and <a href="javascript:showSupportItem('figure2');">Figure 2</a> shows the database schema. The <a href="http://assets.devx.com/sourcecode/14239.tgz">sample application source code</a> contains the following SQL scripts, which you need in order to create and instantiate the corresponding database:
</p><ul><li>src/sql/create.sql: The SQL script used to create the database.</li><li>src/sql/init.sql: Test data</li></ul><p></p><blockquote><b>Note on Installing Maven 2</b><br />
At the time of writing, the Maven 2 repository seemed to be missing
some jars. To get around this problem, find the missing jars in the
root directory of the application source code. To install them in the
Maven 2 repository, go to the app directory and execute the following
instructions:
<pre><code><br />$ mvn install:install-file -DgroupId=javax.security -DartifactId=jacc -Dversion=1.0 <br />    -Dpackaging=jar -Dfile=jacc-1.0.jar<br />$ mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B <br />    -Dpackaging=jar -Dfile=jta-1.0.1B.jar<br /></code></pre></blockquote><p></p><table align="right" border="0" cellpadding="5" cellspacing="0" width="175"><tbody><tr><td valign="top"><a href="javascript:showSupportItem('figure2');"><img alt="" src="http://assets.devx.com/articlefigs/14241.gif" border="0" height="165" width="175" /></a></td><td width="12"> </td></tr><tr><td class="smallfont"><a href="javascript:showSupportItem('figure2');">Figure 2</a>. The Database Schema</td></tr></tbody></table><p></p><h5>Setting Up a Read-Only Cache</h5>
To begin with something simple, here's the Hibernate mapping for the Country class:
<pre><code><br />&lt;hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"&gt;<br />    &lt;class name="Country" table="COUNTRY" dynamic-update="true"&gt;<br />		&lt;meta attribute="implement-equals"&gt;true&lt;/meta&gt;    <br /> 		&lt;cache usage="read-only"/&gt;<br /><br />        &lt;id name="id" type="long" unsaved-value="null" &gt;<br />            &lt;column name="cn_id" not-null="true"/&gt;<br />            &lt;generator class="increment"/&gt;<br />        &lt;/id&gt;<br /><br />	   &lt;property column="cn_code" name="code" type="string"/&gt;<br />	   &lt;property column="cn_name" name="name" type="string"/&gt;<br /><br />	  &lt;set name="airports"&gt;<br />	   &lt;key column="cn_id"/&gt;<br />	   &lt;one-to-many class="Airport"/&gt;<br />	  &lt;/set&gt;<br />    &lt;/class&gt;<br />&lt;/hibernate-mapping&gt;<br /></code></pre><p>Suppose you need to display a list of all countries. You could
implement this with a simple method in the CountryDAO class as follows:
</p><pre><code><br />public class CountryDAO {<br />	...	<br />	public List getCountries() {<br />		return SessionManager.currentSession()<br />					   .createQuery(<br />					      "from Country as c order by c.name")<br />					   .list();<br />	}<br />}<br /></code></pre><p>Because this method is likely to be called often, you need to see
how it behaves under pressure. So write a simple unit test that
simulates five successive calls:
</p><pre><code><br />	public void testGetCountries() {<br />		CountryDAO dao = new CountryDAO();<br />		for(int i = 1; i &lt;= 5; i++) {<br />  		    Transaction tx = SessionManager.getSession().beginTransaction();<br />		    TestTimer timer = new TestTimer("testGetCountries");<br />		    List countries = dao.getCountries();<br />		    tx.commit();<br />		    SessionManager.closeSession();<br />		    timer.done();<br />		    assertNotNull(countries);<br />		    assertEquals(countries.size(),229);<br />		}<br />	}<br /></code></pre><p>You can run this test from either your preferred IDE or the command
line using Maven 2 (the demo application provides the Maven 2 project
files). The demo application was tested using a local MySQL database.
When you run this test, you should get something like the following:
</p><pre><code><br />$mvn test -Dtest=CountryDAOTest<br />...<br />testGetCountries: 521 ms.<br />testGetCountries: 357 ms.<br />testGetCountries: 249 ms.<br />testGetCountries: 257 ms.<br />testGetCountries: 355 ms.<br />[surefire] Running com.wakaleo.articles.caching.dao.CountryDAOTest<br />[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 3,504 sec<br /></code></pre><p>So each call takes roughly a quarter of a second, which is a bit
sluggish by most standards. The list of countries probably doesn't
change very often, so this class would be a good candidate for a
read-only cache. So add one.
</p><p>
You can activate second-level caching classes in one of the two following ways: 
</p><ol><li>You activate it on a class-by-class basis in the *.hbm.xml file, using the cache attribute:
<pre><code><br />&lt;hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"&gt;<br />         &lt;class name="Country" table="COUNTRY" dynamic-update="true"&gt;<br />		&lt;meta attribute="implement-equals"&gt;true&lt;/meta&gt;<br />		&lt;cache usage="read-only"/&gt;<br />            ...			        <br />        &lt;/class&gt;<br />    &lt;/hibernate-mapping&gt;<br /></code></pre></li><li>You can store all cache information in the hibernate.cfg.xml file, using the class-cache attribute:
<pre><code><br />&lt;hibernate-configuration&gt;<br />	&lt;session-factory&gt;<br />		...<br />		&lt;property name="hibernate.cache.provider_class"&gt;<br />			org.hibernate.cache.EHCacheProvider<br />		&lt;/property&gt;<br />		...<br />		&lt;class-cache <br />class="com.wakaleo.articles.caching.businessobjects.Country"<br />usage="read-only"<br />		/&gt;<br />	&lt;/session-factory&gt;<br />&lt;/hibernate-configuration&gt;<br /></code></pre></li></ol><p>Next, you need to configure the cache rules for this class. These
rules determine the nitty-gritty details of how the cache will behave.
The examples in this demo use EHCache, but remember that each cache
implementation is different. </p><p>
EHCache needs a configuration file (generally called ehcache.xml) at
the classpath root. The EHCache configuration file is well documented
on the <a href="http://ehcache.sourceforge.net/documentation" target="new">project Web site</a>.
Basically, you define rules for each class you want to store, as well
as a defaultCache entry for use when you don't explicitly give any
rules for a class. </p><p>
For the first example, you can use the following simple EHCache configuration file:
</p><pre><code><br />&lt;ehcache&gt;<br /><br />    &lt;diskStore path="java.io.tmpdir"/&gt;<br /><br />    &lt;defaultCache<br />        maxElementsInMemory="10000"<br />        eternal="false"<br />        timeToIdleSeconds="120"<br />        timeToLiveSeconds="120"<br />        overflowToDisk="true"<br />        diskPersistent="false"<br />        diskExpiryThreadIntervalSeconds="120"<br />        memoryStoreEvictionPolicy="LRU"<br />        /&gt;<br /><br />    &lt;cache name="com.wakaleo.articles.caching.businessobjects.Country"<br />        maxElementsInMemory="300"<br />        eternal="true"<br />        overflowToDisk="false"<br />        /&gt;<br /><br />&lt;/ehcache&gt;<br /></code></pre><p>
This file basically sets up a memory-based cache for Countries with at
most 300 elements (the country list contains 229 countries). Note that
the cache never expires (the 'eternal=true' property). </p><p>
Now, rerun the tests to see how the cache performs:
</p><pre><code><br />$mvn test -Dtest=CompanyDAOTest<br />...<br />testGetCountries: 412 ms.<br />testGetCountries: 98 ms.<br />testGetCountries: 92 ms.<br />testGetCountries: 82 ms.<br />testGetCountries: 93 ms.<br />[surefire] Running com.wakaleo.articles.caching.dao.CountryDAOTest<br />[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 2,823 sec<br /></code></pre><p>
As you would expect, the first query is unchanged since the first time
around you have to actually load the data. However, all subsequent
queries are several times faster.
</p><p></p><h5>Behind the Scenes</h5>Before moving on, it is useful to look at
what's going on behind the scenes. One thing you should know is that
the Hibernate cache does not store object instances. Instead, it stores
objects in their "dehydrated" form (to use Hibernate terminology), that
is, as a set of property values. The following is a sample of the
contents of the Country cache:
<pre><code><br />{ <br />  30  =&gt; [bw,Botswana,30], <br />  214 =&gt; [uy,Uruguay,214], <br />  158 =&gt; [pa,Panama,158],<br />  31  =&gt; [by,Belarus,31]<br />  95  =&gt; [in,India,95]<br />  ...<br />}<br /></code></pre><p>Notice how each ID is mapped to an array of property values. You may
also have noticed that only the primitive properties are stored; there
is no sign of the airports property. This is because the airports
property is actually an association: a set of references to other
persistent objects. </p><p>
By default, Hibernate does not cache associations. It's up to you to
decide which associations should be cached, and which associations
should be reloaded whenever the cached object is retrieved from the
second-level cache. </p><p>
Association caching is a very powerful functionality. The next section takes a more detailed look at it.
</p><p><br /><br /></p></td>
						</tr>
				</tbody>
		</table>
		<table border="0" cellpadding="0" cellspacing="0">
				<tbody>
						<tr>
								<td>
										<br />
								</td>
						</tr>
						<tr>
								<td>
										<h4>Working with Cached Associations</h4>
Suppose you need to display the list of employees (with employee names,
languages spoken, etc.) for a given country. The following is the
Hibernate mapping of the Employee class:
<pre><code><br />&lt;hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"&gt;<br />    &lt;class name="Employee" table="EMPLOYEE" dynamic-update="true"&gt;<br />		&lt;meta attribute="implement-equals"&gt;true&lt;/meta&gt;    <br /><br />       &lt;id name="id" type="long" unsaved-value="null" &gt;<br />            &lt;column name="emp_id" not-null="true"/&gt;<br />            &lt;generator class="increment"/&gt;<br />       &lt;/id&gt;<br /><br />	 &lt;property column="emp_surname" name="surname" type="string"/&gt;<br />	 &lt;property column="emp_firstname" name="firstname" type="string"/&gt;<br /><br />	 &lt;many-to-one name="country"<br /> 	              column="cn_id"<br />	              class="com.wakaleo.articles.caching.businessobjects.Country"  <br />			  not-null="true" /&gt;<br /><br />	 &lt;!-- Lazy-loading is deactivated to demonstrate caching behavior --&gt;    <br />	 &lt;set name="languages" table="EMPLOYEE_SPEAKS_LANGUAGE" lazy="false"&gt;<br />    	 &lt;key column="emp_id"/&gt;<br />      	    	&lt;many-to-many column="lan_id" class="Language"/&gt;<br />	 &lt;/set&gt;				        <br />    &lt;/class&gt;<br />&lt;/hibernate-mapping&gt;<br /></code></pre><p>Suppose you really need to load the languages spoken by an employee
every time you use the Employee object. To force Hibernate to
automatically load the languages set, you set the lazy attribute to
false. (This is just for the sake of this example. In general,
deactivating lazy loading is not a good idea. Do it only when
absolutely necessary.)
You will also need a DAO class to fetch the employees. The following
one would do the trick:
</p><pre><code><br />public class EmployeeDAO {<br /><br />	public List getEmployeesByCountry(Country country) {<br />		return SessionManager.currentSession()<br />		 .createQuery(<br />		      "from Employee as e where e.country = :country "<br />                + " order by e.surname, e.firstname")<br />		 .setParameter("country",country)<br />		 .list();<br />	}<br />}<br /></code></pre><p>Next, write some simple unit tests to see how it performs. As in the
previous example, you should see how it performs when called
repeatedly: </p><pre><code><br />public class EmployeeDAOTest extends TestCase {<br /><br />	CountryDAO countryDao = new CountryDAO();<br />	EmployeeDAO employeeDao = new EmployeeDAO();<br /><br />	/**<br />	 * Ensure that the Hibernate session is available<br />	 * to avoid the Hibernate initialisation interfering with<br />	 * the benchmarks<br />	 */<br />	protected void setUp() throws Exception {		<br />		super.setUp();<br />		SessionManager.getSession();<br />	}<br /><br />	public void testGetNZEmployees() {<br />		TestTimer timer = new TestTimer("testGetNZEmployees");<br />		Transaction tx = SessionManager.getSession().beginTransaction();<br />		Country nz = countryDao.findCountryByCode("nz");<br />		List kiwis = employeeDao.getEmployeesByCountry(nz);<br />		tx.commit();<br />		SessionManager.closeSession();<br />		timer.done();<br />	}<br /><br />	public void testGetAUEmployees() {<br />		TestTimer timer = new TestTimer("testGetAUEmployees");<br />		Transaction tx = SessionManager.getSession().beginTransaction();<br />		Country au = countryDao.findCountryByCode("au");<br />		List aussis = employeeDao.getEmployeesByCountry(au);	<br />		tx.commit();<br />		SessionManager.closeSession();<br />		timer.done();<br />	}<br /><br />	public void testRepeatedGetEmployees() {<br />		testGetNZEmployees();<br />		testGetAUEmployees();<br />		testGetNZEmployees();<br />		testGetAUEmployees();<br />	}<br />}<br /></code></pre><p>
If you run a test using the above configuration, you should get something like the following:
</p><pre><code><br />$mvn test -Dtest=EmployeeDAOTest<br />...<br /><br />testGetNZEmployees: 1227 ms.<br />testGetAUEmployees: 883 ms.<br />testGetNZEmployees: 907 ms.<br />testGetAUEmployees: 873 ms.<br />testGetNZEmployees: 987 ms.<br />testGetAUEmployees: 916 ms.<br />[surefire] Running com.wakaleo.articles.caching.dao.EmployeeDAOTest<br />[surefire] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 3,684 sec<br /></code></pre><p>
So loading the 50 or so employees assigned to each country takes about
a second each time. That's way too slow. This is typical of the N+1
query problem. If you activate the SQL logs, you will see one query on
the EMPLOYEE table, followed by literally hundreds of queries on the
LANGUAGE table: whenever Hibernate retrieves an employee object from
the cache, it reloads all the associated languages.
So how can you improve on this? The first thing to do is activate
read/write caching on the Employee class as follows:
</p><pre><code><br />	&lt;hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"&gt;<br />        &lt;class name="Employee" table="EMPLOYEE" dynamic-update="true"&gt;<br />		&lt;meta attribute="implement-equals"&gt;true&lt;/meta&gt;<br />		&lt;cache usage="read-write"/&gt;<br />            ...			        <br />        &lt;/class&gt;<br />    &lt;/hibernate-mapping&gt;<br /></code></pre><p>
You should also activate caching on the Language class. Read-only caching should do here:
</p><pre><code><br />    &lt;class name="Language" table="SPOKEN_LANGUAGE" dynamic-update="true"&gt;<br />		&lt;meta attribute="implement-equals"&gt;true&lt;/meta&gt;    <br />		&lt;cache usage="read-only"/&gt;<br />            ...			        <br />        &lt;/class&gt;<br />    &lt;/hibernate-mapping&gt;<br /></code></pre><p>
Then, you will need to configure the cache rules by adding the following entries to the ehcache.xml file: 
</p><pre><code><br />    &lt;cache name="com.wakaleo.articles.caching.businessobjects.Employee"<br />        maxElementsInMemory="5000"<br />        eternal="false"<br />        overflowToDisk="false"<br />        timeToIdleSeconds="300"<br />        timeToLiveSeconds="600"<br />    /&gt;<br />    &lt;cache name="com.wakaleo.articles.caching.businessobjects.Language"<br />        maxElementsInMemory="100"<br />        eternal="true"<br />        overflowToDisk="false"<br />    /&gt;<br /></code></pre><p>This is fine, but it doesn't solve the N+1 query problem: 50 or so
extra queries will still be executed whenever you load an Employee.
This is a case where you need to activate caching on the language
association in the Employee.hbm.xml mapping file, as follows: </p><pre><code><br />&lt;hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"&gt;<br />    &lt;class name="Employee" table="EMPLOYEE" dynamic-update="true"&gt;<br />		&lt;meta attribute="implement-equals"&gt;true&lt;/meta&gt;    <br /><br />      &lt;id name="id" type="long" unsaved-value="null" &gt;<br />            &lt;column name="emp_id" not-null="true"/&gt;<br />            &lt;generator class="increment"/&gt;<br />      &lt;/id&gt;<br /><br />	&lt;property column="emp_surname" name="surname" type="string"/&gt;<br />	&lt;property column="emp_firstname" name="firstname" type="string"/&gt;<br /><br />	&lt;many-to-one name="country"<br /> 	  		 column="cn_id"<br /> 		       class="com.wakaleo.articles.caching.businessobjects.Country"  <br />			not-null="true" /&gt;<br /><br />	&lt;!-- Lazy-loading is deactivated to demonstrate caching behavior --&gt;    <br />      &lt;set name="languages" table="EMPLOYEE_SPEAKS_LANGUAGE" lazy="false"&gt;<br />	    &lt;cache usage="read-write"/&gt;<br />   	    &lt;key column="emp_id"/&gt;<br />    	    &lt;many-to-many column="lan_id" class="Language"/&gt;<br />	&lt;/set&gt;    					        <br />    &lt;/class&gt;<br />&lt;/hibernate-mapping&gt;<br /></code></pre><p>
In this configuration, you should get near-optimal performance:
</p><pre><code><br />$mvn test -Dtest=EmployeeDAOTest<br />...<br />testGetNZEmployees: 1477 ms.<br />testGetAUEmployees: 940 ms.<br />testGetNZEmployees: 65 ms.<br />testGetAUEmployees: 65 ms.<br />testGetNZEmployees: 76 ms.<br />testGetAUEmployees: 52 ms.<br />[surefire] Running com.wakaleo.articles.caching.dao.EmployeeDAOTest<br />[surefire] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0,228 sec<br /></code></pre><p><br /><br /></p></td>
						</tr>
				</tbody>
		</table>
		<table border="0" cellpadding="0" cellspacing="0">
				<tbody>
						<tr>
								<td>
										<br />
								</td>
						</tr>
						<tr>
								<td>
										<h4>Using Query Caches</h4>
In certain cases, it is useful to cache the exact results of a query,
not just certain objects. For example, the getCountries() method
probably should return exactly the same country list each time it is
called. So, in addition to caching the Country class, you could also
cache the query results themselves.
<p>
To do this, you need to set the hibernate.cache.use_query_cache property in the hibernate.cfg.xml file to true, as follows:
</p><pre><code><br />    &lt;property name="hibernate.cache.use_query_cache"&gt;true&lt;/property&gt;<br /></code></pre><p>
Then, you use the setCacheable() method as follows on any query you wish to cache:
</p><pre><code><br />public class CountryDAO {<br /><br />    public List getCountries() {<br />        return SessionManager.currentSession()<br />                             .createQuery("from Country as c order by c.name")<br />				     .setCacheable(true)<br />                             .list();<br />    }<br />}<br /></code></pre><p>To guarantee the non-staleness of cache results, Hibernate expires
the query cache results whenever cached data is modified in the
application. However, it cannot anticipate any changes made by other
applications directly in the database. So you should not use <i>any</i>
second-level caching (or configure a short expiration timeout for
class- and collection-cache regions) if your data has to be up-to-date
all the time.
</p><p></p><h4>Proper Hibernate Caching</h4>Caching is a powerful technique,
and Hibernate provides a powerful, flexible, and unobtrusive way of
implementing it. Even the default configuration can provide substantial
performance improvements in many simple cases. However, like any
powerful tool, Hibernate needs some thought and fine-tuning to obtain
optimal results, and caching—like any other optimization
technique—should be implemented using an incremental, test-driven
approach. When done correctly, a small amount of well executed caching
can boost your applications to their maximum capacities.
<p></p><div class=""><i><b>John Ferguson Smart</b>
has worked on many large-scale J2EE projects involving international
and offshore teams for government and business entities. His
specialties are J2EE architecture and development and IT project
management. He also has a broad experience with open source Java
technologies. Check out his technical blog at
<a href="http://www.jroller.com/page/wakaleo" target="new">www.jroller.com/page/wakaleo</a>.</i></div></td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/leedo/aggbug/37004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-03-23 11:25 <a href="http://www.blogjava.net/leedo/articles/37004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate二级缓存攻略(转自java视线)</title><link>http://www.blogjava.net/leedo/articles/36991.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Thu, 23 Mar 2006 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/36991.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/36991.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/36991.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/36991.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/36991.html</trackback:ping><description><![CDATA[
		<span class="postbody">很多人对二级缓存都不太了解，或者是有错误的认识，我一直想写一篇文章介绍一下hibernate的二级缓存的，今天终于忍不住了。
<br />
我的经验主要来自hibernate2.1版本，基本原理和3.0、3.1是一样的，请原谅我的顽固不化。
<br /><br />
hibernate的session提供了一级缓存，每个session，对同一个id进行两次load，不会发送两条sql给数据库，但是session关闭的时候，一级缓存就失效了。
<br /><br />
二级缓存是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
<br /><br /><br />
缓存可以简单的看成一个Map，通过key在缓存里面找value。
<br /><br /><span style="font-weight: bold;">Class的缓存</span><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查询的结果缓存，就要用到查询缓存了
<br /><br /><span style="font-weight: bold;">查询缓存</span><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
<br /><br />
对于查询缓存来说，缓存的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 /><span style="font-weight: bold;">这里还有一个很容易被忽视的重要问题，即打开查询缓存以后，即使是list方法也可能遇到1+N的问题！</span>相
同条件第一次list的时候，因为查询缓存中找不到，不管class缓存是否存在数据，总是发送一条sql语句到数据库获取全部数据，然后填充查询缓存和
class缓存。但是第二次执行的时候，问题就来了，如果你的class缓存的超时时间比较短，现在class缓存都超时了，但是查询缓存还在，那么
list方法在获取id串以后，将会一个一个去数据库load！因此，class缓存的超时时间一定不能短于查询缓存设置的超时时间！如果还设置了发呆时
间的话，保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况，比如class缓存被程序强制evict了，这种情况就请自己注意
了。
<br /><br />
另外，如果hql查询包含select字句，那么查询缓存里面的value就是整个结果集了。
<br /><br />
当hibernate更新数据库的时候，它怎么知道更新哪些查询缓存呢？
<br />
hibernate在一个地方维护每个表的最后更新时间，其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
<br />当通过hibernate更新的时候，hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时
间和这个缓存所查询的表，当hibernate查询一个缓存是否存在的时候，如果缓存存在，它还要取出缓存的生成时间和这个缓存所查询的表，然后去查找这
些表的最后更新时间，如果有一个表在生成时间后更新过了，那么这个缓存是无效的。
<br />
可以看出，只要更新过一个表，那么凡是涉及到这个表的查询缓存就失效了，因此查询缓存的命中率可能会比较低。
<br /><br /><span style="font-weight: bold;">Collection缓存</span><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缓存里面的顺序没有做更新。
<br /><br /><span style="font-weight: bold;">缓存策略</span><br />
只读缓存（read-only）：没有什么好说的
<br />
读/写缓存（read-write）:程序可能要的更新数据
<br />
不严格的读/写缓存（nonstrict-read-write）：需要更新数据，但是两个事务更新同一条记录的可能性很小，性能比读写缓存好
<br />
事务缓存（transactional）：缓存支持事务，发生异常的时候，缓存也能够回滚，只支持jta环境，这个我没有怎么研究过
<br /><br />
读写缓存和不严格读写缓存在实现上的区别在于，读写缓存更新缓存的时候会把缓存里面的数据换成一个锁，其他事务如果去取相应的缓存数据，发现被锁住了，然后就直接取数据库查询。
<br />
在hibernate2.1的ehcache实现中，如果锁住部分缓存的事务发生了异常，那么缓存会一直被锁住，直到60秒后超时。
<br />
不严格读写缓存不锁定缓存中的数据。
<br /><br /><br /><span style="font-weight: bold;">使用二级缓存的前置条件</span><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代码到处都是，在你添加一个查询缓存的时候，还知道其他什么地方也要做相应的改动吗？
<br /><br />
----------------------------------------------------
<br /><br /><span style="font-weight: bold;">总结：</span><br />
不要想当然的以为缓存一定能提高性能，仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的，不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用，可能会有1+N的问题。不当的使用还可能导致读出脏数据。
<br />
如果受不了hibernate的诸多限制，那么还是自己在应用程序的层面上做缓存吧。
<br />在越高的层面上做缓存，效果就会越好。就好像尽管磁盘有缓存，数据库还是要实现自己的缓存，尽管数据库有缓存，咱们的应用程序还是要做缓存。因为
底层的缓存它并不知道高层要用这些数据干什么，只能做的比较通用，而高层可以有针对性的实现缓存，所以在更高的级别上做缓存，效果也要好些吧。
<br /><br /><br />
终于写完了，好累……</span>
<img src ="http://www.blogjava.net/leedo/aggbug/36991.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-03-23 10:04 <a href="http://www.blogjava.net/leedo/articles/36991.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化hibernate性能的几点建议</title><link>http://www.blogjava.net/leedo/articles/36974.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Thu, 23 Mar 2006 01:29:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/36974.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/36974.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/36974.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/36974.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/36974.html</trackback:ping><description><![CDATA[
		<div align="left">
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td id="zxtitle_8union" align="center" height="50">
												<b style="color: rgb(255, 0, 0); font-size: 14pt; line-height: 30pt;">
优化hibernate性能的几点建议</b>
										</td>
								</tr>
								<tr>
										<td align="center" bgcolor="#f1f1fa">
来源：博客园     2006-3-10 22:01:00</td>
								</tr>
						</tbody>
				</table>
				<table border="0" cellpadding="0" cellspacing="0" width="97%">
						<tbody>
								<tr>
										<td> </td>
								</tr>
								<tr>
										<td style="padding-left: 8pt; padding-right: 8pt; font-size: 14px; line-height: 22px;">
　　1、针对oracle数据库而言，Fetch Size
是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数，一般设置为30、50、100。Oracle数据库的JDBC驱动默认
的Fetch Size=15，设置Fetch
Size设置为：30、50，性能会有明显提升，如果继续增大，超出100，性能提升不明显，反而会消耗内存。<br /><br />　　即在hibernate配制文件中进行配制：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>1 ＜property name="hibernateProperties"＞<br />2 ＜props＞<br />3 ＜prop key="hibernate.dialect"＞org.hibernate.dialect.Oracle9Dialect＜/prop＞<br />4 ＜prop key="hibernate.show_sql"＞false＜/prop＞<br />5 ＜!-- Create/update the database tables automatically when the JVM starts up<br />6 ＜prop key="hibernate.hbm2ddl.auto"＞update＜/prop＞ --＞<br />7 ＜!-- Turn batching off for better error messages under PostgreSQL <br />8 ＜prop key="hibernate.jdbc.batch_size"＞100＜/prop＞ --＞<br />9 ＜prop key="hibernate.jdbc.batch_size"＞50＜/prop＞<br />10 ＜/props＞<br />11 ＜/property＞Fetch Size设的越大，读数据库的次数越少，速度越快；Fetch Size越小，读数据库的次数越多，速度越慢。</td></tr></tbody></table><br />　　2、如果是超大的系统，建议生成htm文件。加快页面提升速度。<br /><br />　　3、不要把所有的责任推在hibernate上，对代码进行重构，减少对数据库的操作，尽量避免在数据库查询时使用in操作，以及避免递归查询操作，代码质量、系统设计的合理性决定系统性能的高低。<br /><br />　　4、 对大数据量查询时，慎用list()或者iterator()返回查询结果， <br /><br />　　（1）. 使用List()返回结果时，Hibernate会所有查询结果初始化为持久化对象，结果集较大时，会占用很多的处理时间。 <br /><br />　
　（2）.
而使用iterator()返回结果时，在每次调用iterator.next()返回对象并使用对象时，Hibernate才调用查询将对应的对象初始
化，对于大数据量时，每调用一次查询都会花费较多的时间。当结果集较大，但是含有较大量相同的数据，或者结果集不是全部都会使用时，使用iterator
()才有优势。<br /><br />　　5、在一对多、多对一的关系中，使用延迟加载机制，会使不少的对象在使用时方会初始化，这样可使得节省内存空间以及减少数据库的负荷，而且若PO中的集合没有被使用时，就可减少互数据库的交互从而减少处理时间。 <br /><br />　　6、对含有关联的PO（持久化对象）时，若default-cascade="all"或者 “save-update”，新增PO时，请注意对PO中的集合的赋值操作，因为有可能使得多执行一次update操作。 <br /><br />　
　7、
对于大数据量新增、修改、删除操作或者是对大数据量的查询，与数据库的交互次数是决定处理时间的最重要因素，减少交互的次数是提升效率的最好途径，所以在
开发过程中，请将show_sql设置为true，深入了解Hibernate的处理过程，尝试不同的方式，可以使得效率提升。尽可能对每个页面的显示，
对数据库的操作减少到100----150条以内。越少越好。<br /><br />　　以上是在进行struts+hibernate+spring进行项目开发中，对hibernate性能优化的几点心得。</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.blogjava.net/leedo/aggbug/36974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-03-23 09:29 <a href="http://www.blogjava.net/leedo/articles/36974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate学习心得--性能优化 </title><link>http://www.blogjava.net/leedo/articles/36971.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Thu, 23 Mar 2006 01:24:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/36971.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/36971.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/36971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/36971.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/36971.html</trackback:ping><description><![CDATA[
		<br />
		<dl class="ReadArticle">
				<dd class="ArticleInfo">
								作者：
								∣来源：<a id="HyFromWhere" href="../../rss.aspx?id=-1" target="_blank">BlogJava</a>∣<a id="HyHistoryUrl" title="http://www.blogjava.net/flyingis/archive/2005/11/15/19809.html" href="../../flyingis/archive/2005/11/15/19809.html" target="_blank">原文地址</a>∣<span id="LblUpdateDate">2005-11-15</span></dd>
				<dd class="ArticleContent">
						<div class="HideDiv" style="overflow: hidden; width: 100%;">
								<span id="LblContent">
										<font size="2">   
在使用Hibernate进行查询的时候大家都会用到Hibernate缓存，其中Session缓存即一块内存空间，存放了相互关联的Java对象，这
些位于Session缓存中的对象就是持久化对象，Session根据持久化对象的状态变化来同步更新数据库。这个Session缓存是
Hibernate的一级缓存。此外，SessionFactory有一个内置缓存和一个外置缓存，即Hibernate的第二级缓存。而
Hibernate正是由于这些缓存的存在，才使得其数据库操作效率提高，就是说，在提供了方便易操作的操作数据库数据的方式的同时保证了工作效率，但是
不能因此而免去后顾之忧，需要在设计业务逻辑层的时候考虑使用最优的架构，节省有效的系统资源。在查询方面，Hibernate主要从以下几个方面来优化
查询性能：<br /><br />1.降低访问数据库的频率，减少select语句的数目。实现手段包括：<br /><br />    使用迫切左外连接或迫切内连接检索策略。<br />    对延迟检索或立即检索策略设置批量检索数目。<br />    使用查询缓存。<br /><br />2.避免多余加载程序不需要访问的数据。实现手段包括：<br /><br />    使用延迟检索策略。<br />    使用集合过滤。<br /><br />3.避免报表查询数据占用缓存。实现手段为利用投影查询功能，查询出实体的部分属性。<br /><br />4.减少select语句中的字段，从而降低访问数据库的数据量。实现手段为利用Query的iterate()方法。<br /></font>
										<font size="2">
												<br />   
在插入和更新数据时，要控制insert和update语句，合理设置映射属性来保证插入更新的性能，例如，当表中包含许多字段时，建议把dynamic
-update属性和dynamic-update属性都设为true，这样在insert和update语句中就只包含需要插入或更新的字段，这可以节
省数据库执行SQL语句的时间，从而提高应用的运行性能。</font>
										<p>
												<font size="2">    还有什么其它的提升性能的方式希望和大家一起讨论。</font>
										</p>
								</span>
						</div>
				</dd>
		</dl>
<img src ="http://www.blogjava.net/leedo/aggbug/36971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-03-23 09:24 <a href="http://www.blogjava.net/leedo/articles/36971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 延迟初始化错误（ERROR LazyInitializer）是如何产生的?</title><link>http://www.blogjava.net/leedo/articles/36970.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Thu, 23 Mar 2006 01:22:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/36970.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/36970.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/36970.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/36970.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/36970.html</trackback:ping><description><![CDATA[
		<div class="title">
				<h2>Hibernate 延迟初始化错误（ERROR LazyInitializer）是如何产生的?(转自Matrix)</h2>
				<a href="http://www.matrix.org.cn/user.shtml;jsessionid=A0135EA7CE3E4EAB2CBAC61D49CA495E?userid=55775">wldandan</a>
		发表于 2005-09-23<br />
		点击数:1368 评论数:3 评价:0/0<br />
		关键词:ERROR LazyInitialize
</div>
		<!-- end of div title -->
		<div class="summary">
				<div class="left">
				</div>
				<div class="center">
						<h4>摘要:</h4>
		延迟初始化错误是运用Hibernate开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略，那么必须当代理类实例或代理集合处于持久化状态（即处于Session范围内）时，才能初始化它。如果在游离状态时才初始化它，就会产生延迟初始化错误。
	</div>
				<div class="right">
						<div class="help">
								<br />
						</div>
				</div>
		</div>
		<!-- end of summary line -->


	延迟初始化错误（ERROR LazyInitializer）是如何产生的?<br /><br />
选自&lt;&lt;精通Hibernate：Java对象持久化技术详解&gt;&gt; 作者：孙卫琴 来源:www.javathinker.org<br /><br />
延迟初始化错误是运用Hibernate开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略，那么必须当代理类实例或代理集合处于持久化状态（即处于Session范围内）时，才能初始化它。如果在游离状态时才初始化它，就会产生延迟初始化错误。<br /><br />
下面把Customer.hbm.xml文件的&lt;class&gt;元素的lazy属性设为true，表示使用延迟检索策略：<br />
&lt;class name="mypack.Customer" table="CUSTOMERS" lazy="true"&gt;<br />
当执行Session的load()方法时，Hibernate不会立即执行查询CUSTOMERS表的select语句，仅仅返回Customer类的代理类的实例，这个代理类具由以下特征：<br />
（1） 由Hibernate在运行时动态生成，它扩展了Customer类，因此它继承了Customer类的所有属性和方法，但它的实现对于应用程序是透明的。<br />
（2） 当Hibernate创建Customer代理类实例时，仅仅初始化了它的OID属性，其他属性都为null，因此这个代理类实例占用的内存很少。<br />
（3）
当应用程序第一次访问Customer代理类实例时（例如调用customer.getXXX()或customer.setXXX()方法），
Hibernate会初始化代理类实例，在初始化过程中执行select语句，真正从数据库中加载Customer对象的所有数据。但有个例外，那就是当
应用程序访问Customer代理类实例的getId()方法时，Hibernate不会初始化代理类实例，因为在创建代理类实例时OID就存在了，不必
到数据库中去查询。<br /><br />
提示：Hibernate采用CGLIB工具来生成持久化类的代理类。CGLIB是一个功能强大的Java字节码生成
工具，它能够在程序运行时动态生成扩展Java类或者实现Java接口的代理类。关于CGLIB的更多知识，请参考：http:
//cglib.sourceforge.net/。<br />
以下代码先通过Session的load()方法加载Customer对象，然后访问它的name属性： <br /><pre class="overflow">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />customer.getName();<br />tx.commit();</pre><br /><br />
在
运行session.load()方法时Hibernate不执行任何select语句，仅仅返回Customer类的代理类的实例，它的OID为1，这
是由load()方法的第二个参数指定的。当应用程序调用customer.getName()方法时，Hibernate会初始化Customer代理
类实例，从数据库中加载Customer对象的数据，执行以下select语句：<br /><pre class="overflow">select * from CUSTOMERS where ID=1;<br />select * from ORDERS where CUSTOMER_ID=1;</pre><br /><br />
当&lt;class&gt;元素的lazy属性为true，会影响Session的load()方法的各种运行时行为，下面举例说明。<br /><br />
1．如果加载的Customer对象在数据库中不存在，Session的load()方法不会抛出异常，只有当运行customer.getName()方法时才会抛出以下异常：<br /><pre class="overflow">ERROR LazyInitializer:63 - Exception initializing proxy<br />net.sf.hibernate.ObjectNotFoundException: No row with the given identifier exists: 1, of class: <br />mypack.Customer</pre><br /><br />
2．如果在整个Session范围内，应用程序没有访问过Customer对象，那么Customer代理类的实例一直不会被初始化，Hibernate不会执行任何select语句。以下代码试图在关闭Session后访问Customer游离对象：<br /><pre class="overflow">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />tx.commit();<br />session.close();<br />customer.getName();</pre><br /><br />
由于引用变量customer引用的Customer代理类的实例在Session范围内始终没有被初始化，因此在执行customer.getName()方法时，Hibernate会抛出以下异常：<br /><pre class="overflow">ERROR LazyInitializer:63 - Exception initializing proxy<br />net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed</pre><br />
由此可见，Customer代理类的实例只有在当前Session范围内才能被初始化。<br /><br />
3．net.sf.hibernate.Hibernate类的initialize()静态方法用于在Session范围内显式初始化代理类实例，isInitialized()方法用于判断代理类实例是否已经被初始化。例如：<br /><pre class="overflow">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />if(!Hibernate.isInitialized(customer)) <br />Hibernate.initialize(customer);<br />tx.commit();<br />session.close();<br />customer.getName();</pre><br />
以上代码在Session范围内通过Hibernate类的initialize()方法显式初始化了Customer代理类实例，因此当Session关闭后，可以正常访问Customer游离对象。<br /><br />
4．当应用程序访问代理类实例的getId()方法时，不会触发Hibernate初始化代理类实例的行为，例如：<br /><pre class="overflow">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />customer.getId();<br />tx.commit();<br />session.close();<br />customer.getName();</pre><br /><br />
当
应用程序访问customer.getId()方法时，该方法直接返回Customer代理类实例的OID值，无需查询数据库。由于引用变量
customer始终引用的是没有被初始化的Customer代理类实例，因此当Session关闭后再执行customer.getName()方法，
Hibernate会抛出以下异常：<br /><pre class="overflow">ERROR LazyInitializer:63 - Exception initializing proxy<br />net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed</pre><img src ="http://www.blogjava.net/leedo/aggbug/36970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-03-23 09:22 <a href="http://www.blogjava.net/leedo/articles/36970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate中的过滤集合类Filtering collections（转）</title><link>http://www.blogjava.net/leedo/articles/31898.html</link><dc:creator>阳光</dc:creator><author>阳光</author><pubDate>Wed, 22 Feb 2006 01:05:00 GMT</pubDate><guid>http://www.blogjava.net/leedo/articles/31898.html</guid><wfw:comment>http://www.blogjava.net/leedo/comments/31898.html</wfw:comment><comments>http://www.blogjava.net/leedo/articles/31898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leedo/comments/commentRss/31898.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leedo/services/trackbacks/31898.html</trackback:ping><description><![CDATA[<p><font style="background-color: rgb(255, 254, 255);"><a href="http://dev.21tx.com/java/struts/" target="_blank">Hibernate</a>的文档中写道:集合<span class="emphasis"><em>filter</em></span>是一种特殊的查询，用于一个持久化集合或者数组。查询字符串可以引用<tt class="literal">this</tt>,意为当前的数组元素<br><br>我觉得这样理解起来有些费劲.其实他的作用就是把你不需要的数据过滤掉,然后把结果集返回给你.现在举个例子说明一下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#0000ff">String hql =&nbsp; "select p from Picgroup p join p.images t where p.id=" + groupid;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Query query = session.createQuery(hql);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List list = query.list();</font></font></p>

<p><font style="background-color: rgb(255, 254, 255);" color="#0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Picgroup group = (Picgroup) list.get(0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; view.setName(group.getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; view.setId(groupid);</font></p>

<font style="background-color: rgb(255, 254, 255);"><font color="#0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Collection image=session.filter(group.getImages(),"select this where
this.state='C'");//这里只取出state等于C的数据<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator ite = image.iterator();</font><br><br>看,就这么简单.一般在一对多或者多对多关系中从一方取另外一方数据时使用.</font><img src ="http://www.blogjava.net/leedo/aggbug/31898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leedo/" target="_blank">阳光</a> 2006-02-22 09:05 <a href="http://www.blogjava.net/leedo/articles/31898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>