﻿<?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-Vincent-随笔分类-Hibernate</title><link>http://www.blogjava.net/lijiajia418/category/14363.html</link><description>Vicent's blog</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 20:24:35 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 20:24:35 GMT</pubDate><ttl>60</ttl><item><title>Hibernate Validator 简介</title><link>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67094.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Fri, 01 Sep 2006 06:05:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67094.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/67094.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/67094.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/67094.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#008000">在项目的业务属性中,你是不是要经常验证属性的取值范围呢. 想要了解比较优美的解决方案吗?           </font>
		</p>
		<p align="left">
				<font color="#008000">看看Hibernate Validator 是怎么做的吧.一见到她,相信你就会说: Oh God, 这就是我需要的.</font>
		</p>
		<p align="left">
				<span style="COLOR: red">任何获得Matrix授权的网站，转载请保留以下作者信息和链接：</span>
				<br />作者：icess(作者的blog:<a href="http://blog.matrix.org.cn/page/icess" target="_new">http://blog.matrix.org.cn/page/icess</a>)<br />关键字：Hibernate Validator</p>
		<p>用Annotations 给类或者类的属性加上约束(constraint),在运行期检查属性值是很优雅的.Hibernate Validator就是这样的一个框架.该框架是十分容易的(就像参考文档中宣称的那样),几乎没有什么学习曲线,Validator 是一个验证框架 不需要和Hibernate的其他部分绑定就可以使用,只要在你的项目中添加Hibernate-annotations.jar库就可以了.那么下面就让我们看看怎么使用吧.</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">Person.java 类</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">/*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* Created on 2006-1-12 Person.java</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* @author </font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">*/</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Length;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Min;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Valid;</font>
						<br />　</code>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">/<font color="#808000">/@Serializability  //测试自定义约束</font></span>
						</font>
				</code>
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">Person {</font>
						<br />
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private </b>
						</font>
						<font color="#000000">String name;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private int </b>
						</font>
						<font color="#000000">age;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private </b>
						</font>
						<font color="#000000">Address address;</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">Person() {}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#ff0000">@Valid //注意此处</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">Address getAddress() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">address;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setAddress(Address address) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.address = address;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Min(value = </font>
						<font color="#990000">1</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public int </b>
						</font>
						<font color="#000000">getAge() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">age;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setAge(</font>
						<font color="#7f0055">
								<b>int </b>
						</font>
						<font color="#000000">age) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.age = age;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Length(min = </font>
						<font color="#990000">4</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">String getName() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">name;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setName(String name) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.name = name;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<p align="left">　</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">Address.java 类</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">/*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* Created on 2006-1-12 Address.java</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* @author </font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">*/</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Length;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Max;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Min;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">Address {</font>
						<br />
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private </b>
						</font>
						<font color="#000000">String street;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private int </b>
						</font>
						<font color="#000000">num;</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">Address() {}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Min(value = </font>
						<font color="#990000">1</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Max(value = </font>
						<font color="#990000">100</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public int </b>
						</font>
						<font color="#000000">getNum() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">num;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setNum(</font>
						<font color="#7f0055">
								<b>int </b>
						</font>
						<font color="#000000">num) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.num = num;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Length(min = </font>
						<font color="#990000">3</font>
						<font color="#000000">,max = </font>
						<font color="#990000">8</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">String getStreet() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">street;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setStreet(String street) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.street = street;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<div class="java" align="left">
				<p>上面是两个用 Validator Annotations 注释的 类. 每个属性都用 约束限制了.  下面看看测试的类吧:</p>
		</div>
		<p align="left">
				<!-- ======================================================== -->
				<!-- = Java Sourcecode to HTML automatically converted code = -->
				<!-- =   Java2Html Converter V4.1 2004 by Markus Gebhard  markus@jave.de   = -->
				<!-- =     Further information: http://www.java2html.de     = -->
				<font color="#000000">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">TestValidator.java 类</code>
				</font>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">/*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* Created on 2006-1-12</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* @author icerain</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">*/</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.ClassValidator;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.InvalidValue;</font>
						<br />
						<br />
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">TestValidator {</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">test() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">Address add = </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">Address();</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">add.setNum(</font>
						<font color="#990000">0</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">add.setStreet(</font>
						<font color="#2a00ff">"1"</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">Person p = </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">Person();</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">p.setAddress(add);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">p.setAge(</font>
						<font color="#990000">0</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">p.setName(</font>
						<font color="#2a00ff">"ice"</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#3f5fbf">/******************Test validator ********/</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#000000">    </font>
						<font color="#ff0000">// 注意该处只验证了Person 为了说明 @Valid 注释的使用</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">ClassValidator&lt;Person&gt; classValidator = </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">ClassValidator&lt;Person&gt; (Person.</font>
						<font color="#7f0055">
								<b>class</b>
						</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">InvalidValue[] validMessages = classValidator.getInvalidValues(p);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>for </b>
						</font>
						<font color="#000000">(InvalidValue value : validMessages) {</font>
						<br />
						<font color="#ffffff">      </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">System.out.println(</font>
						<font color="#2a00ff">"InvalidValue 的长度是:" </font>
						<font color="#000000">+ validMessages.length</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">" . 验证消息是: " </font>
						<font color="#000000">+ value.getMessage() </font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+ </font>
						<font color="#2a00ff">" . PropertyPath 是:" </font>
						<font color="#000000">+ value.getPropertyPath()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">" .\n\t PropertyName 是: " </font>
						<font color="#000000">+value.getPropertyName()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+ </font>
						<font color="#2a00ff">"Value 是: " </font>
						<font color="#000000">+ value.getValue()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">" Bean 是: "</font>
						<font color="#000000">+ value.getBean()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">"\n\t BeanClass 是:" </font>
						<font color="#000000">+ value.getBeanClass());</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public static void </b>
						</font>
						<font color="#000000">main(String[] args) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">TestValidator().test();</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<p align="left">　</p>
		<p align="left">程序的输出如下 <font size="2"><p align="left"><font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 必须大于等于 1 . PropertyPath 是:age .</font></p><p align="left"><font color="#ff00ff">PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@dd87b2</font></p><p align="left"><font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font></p><p align="left"><font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 长度必须介于 4 与 2147483647 之间 . PropertyPath 是:name .</font></p><p align="left"><font color="#ff00ff">PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@dd87b2</font></p><p align="left"><font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font></p><p align="left"><font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 必须大于等于 1 . PropertyPath 是:address.num .</font></p><p align="left"><font color="#ff00ff">PropertyName 是: num. Value 是: 0 Bean 是: test.annotation.validator.Address@197d257</font></p><p align="left"><font color="#ff00ff">BeanClass 是:class test.annotation.validator.Address</font></p><p align="left"><font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 长度必须介于 3 与 8 之间 . PropertyPath 是:address.street .</font></p><p align="left"><font color="#ff00ff">PropertyName 是: street. Value 是: 1 Bean 是: test.annotation.validator.Address@197d257</font></p><p align="left"><font color="#ff00ff">BeanClass 是:class test.annotation.validator.Address</font></p><p align="left">可以看出不满足约束的值都被指出了.</p><p align="left">同时该句: <code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">ClassValidator&lt;Person&gt; classValidator = </font><font color="#7f0055"><b>new </b></font><font color="#000000">ClassValidator&lt;Person&gt; (Person.</font><font color="#7f0055"><b>class</b></font><font color="#000000">);</font></code></p><p align="left">我们只验证了 Person. 在Person里面的Address的属性 由于有<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#ff0000">@Valid Annotations </font>所以 Address的相关属性也被机联验证了 .</code></p><p align="left"><code><span style="FONT-FAMILY: 'Courier New',Courier">如果 把</span></code><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#ff0000">@Valid Annotations </font>去掉,结果如下:</code></p><p align="left"><font color="#ff00ff">InvalidValue 的长度是:2 . 验证消息是: 必须大于等于 1 . PropertyPath 是:age .</font></p><p align="left"><font color="#ff00ff">PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@18fef3d</font></p><p align="left"><font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font></p><p align="left"><font color="#ff00ff">InvalidValue 的长度是:2 . 验证消息是: 长度必须介于 4 与 2147483647 之间 . PropertyPath 是:name .</font></p><p align="left"><font color="#ff00ff">PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@18fef3d</font></p><p align="left"><font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font></p></font></p>
		<p>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">可以看出 没有验证 Address.</span>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">当然了 ,你还可以只验证一个属性 , 没有必要验证整个类.只需要在调用</span>
						<font face="Courier New, Courier">classValidator.getInvalidValues(p,"age")方法时 加上你要验证的属性就可以了.如我们只想验证age 属性 把代码改为如下所示:</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" color="#ff0000">InvalidValue[] validMessages = classValidator.getInvalidValues(p,"age"); /</font>
						<font face="Courier New, Courier" color="#0000ff">/只验证age 属性</font>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">运行结果如下:</span>
				</code>
		</p>
		<p align="left">
				<font color="#ff00ff">InvalidValue 的长度是:1 . 验证消息是: 必须大于等于 1 . PropertyPath 是:age .</font>
		</p>
		<p align="left">
				<font color="#ff00ff">PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@1457cb</font>
		</p>
		<p align="left">
				<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">只是验证了 age 属性.</span>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">怎么样 ,很简单吧. 关于 Hibernate Validator 内建的验证Annotations 大家可以看看 API 或者 参考文档(中文版我正在翻译中 请访问我的 <a href="http://blog.matrix.org.cn/page/icess">Blog </a>获得最新信息).</span>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">如果你要写自己的约束呢 , 你不用担心 ,这也是很容易的. </span>
				</code>任何约束有两部分组成: [约束描述符 即注释]the constraint <span class="emphasis"><em>descriptor</em></span> (the annotation) 和[约束validator 即 实现类] the constraint <span class="emphasis"><em>validator</em></span> (the implementation class).<code><span style="FONT-FAMILY: 'Courier New',Courier">下面我们扩展Hibernate Test suit 中的一个Test 来讲解一下.</span></code></p>
		<font size="2">
				<p align="left">
						<code>
								<span style="FONT-FAMILY: 'Courier New',Courier">首先: 要声明一个</span>
						</code>constraint <span class="emphasis"><em>descriptor .如下:</em></span></p>
				<p align="left">
						<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
								<font color="#7f0055">
										<b>package </b>
								</font>
								<font color="#000000">test.annotation.validator;</font>
								<br />
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">java.lang.annotation.Documented;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.ElementType.TYPE;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.ElementType.FIELD;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.ElementType.METHOD;</font>
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">java.lang.annotation.Retention;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.RetentionPolicy.RUNTIME;</font>
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">java.lang.annotation.Target;</font>
								<br />
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">org.hibernate.validator.ValidatorClass;</font>
								<br />
								<br />
								<font color="#3f5fbf">/**</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">* Dummy sample of a bean-level validation annotation</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">*</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">* </font>
								<font color="#7f9fbf">@author </font>
								<font color="#3f5fbf">Emmanuel Bernard</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">*/</font>
								<br />
								<font color="#000000">@ValidatorClass(SerializabilityValidator.</font>
								<font color="#7f0055">
										<b>class</b>
								</font>
								<font color="#000000">)</font>
								<br />
								<font color="#000000">@Target({METHOD,FIELD,TYPE})</font>
								<br />
								<font color="#000000">@Retention(RUNTIME)</font>
								<br />
								<font color="#000000">@Documented</font>
								<br />
								<font color="#7f0055">
										<b>public </b>
								</font>
								<font color="#000000">@interface Serializability {</font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#7f0055">
										<b>int </b>
								</font>
								<font color="#000000">num() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#990000">11</font>
								<font color="#000000">; </font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#000000">String message() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#2a00ff">"bean must be serialiable"</font>
								<font color="#000000">;</font>
								<br />
								<font color="#000000">}</font>
						</code>
				</p>
		</font>
		<p align="left">
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#000000">@ValidatorClass(SerializabilityValidator.</font>
								<font color="#7f0055">
										<b>class</b>
								</font>
								<font color="#000000">) 指出了 </font>
						</code>constraint <span class="emphasis"><em>validator 类.</em></span></font>
		</p>
		<p align="left">
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#000000">@Target({METHOD,FIELD,TYPE})</font>
								<br />
								<font color="#000000">@Retention(RUNTIME)</font>
								<br />
								<font color="#000000">@Documented                 </font>
						</code>
				</font>
		</p>
		<p align="left">
				<code style="FONT-FAMILY: 'Courier New',Courier">
						<font color="#000000">这几个我就不用解释了吧.</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-FAMILY: 'Courier New',Courier">
						<font color="#000000">Serializability 里面声明了一个 message 显示约束的提示信息. num 只是为了说明一个方面 在这里面没有实际用途用 .</font>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">然后就是 实现一个</span>
				</code>constraint <em><span class="emphasis">validator 类 该类要实现</span></em><tt class="literal">Validator&lt;ConstraintAnnotation&gt;</tt><em><span class="emphasis">.这里是</span></em><font size="2"><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">SerializabilityValidator.java 如下:</font></code></font></p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">//$Id: SerializabilityValidator.java,v 1.3 2005/11/17 18:12:11 epbernard Exp $</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">java.io.Serializable;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Validator;</font>
						<br />
						<br />
						<font color="#3f5fbf">/**</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">* Sample of a bean-level validator</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">* </font>
						<font color="#7f9fbf">@author </font>
						<font color="#3f5fbf">Emmanuel Bernard</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">*/</font>
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">SerializabilityValidator </font>
						<font color="#7f0055">
								<b>implements </b>
						</font>
						<font color="#000000">Validator&lt;Serializability&gt;, Serializable {</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public boolean </b>
						</font>
						<font color="#000000">isValid(Object value) {</font>
						<br />
						<font color="#ffffff">   </font>
						<font color="#00ff00">//这里只是Validator 里面的 实现验证规则的 方法. value 是要验证的值.</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">System.out.println(</font>
						<font color="#2a00ff">"IN SerializabilityValidator isValid:"</font>
						<font color="#000000">+value.getClass()+</font>
						<font color="#2a00ff">": " </font>
						<font color="#000000">+value.toString()); </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>value<font color="#3f7f5f"> </font><font color="#800080">instanceof</font><font color="#3f7f5f"> </font>Serializable<font color="#3f7f5f">;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">initialize(Serializability parameters) {</font><br /><font color="#ffffff">    </font><font color="#3f7f5f">// 在这里可以 取得 </font></code>
				<font size="2">constraint <em><span class="emphasis">descriptor 里面的属性 如上面我们声明的 num </span></em></font>
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">System.out.println(</font>
						<font color="#2a00ff">"IN SerializabilityValidator: parameters:"</font>
						<font color="#000000">+ parameters.num() );</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<p align="left">然后在你的类中应用@<font size="2"><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">Serializability  就可以约束一个类实现</font></code></font><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">Serializable 接口了. 如下:</code></p>
		<p align="left">在我们的Person.java类 添加@<font size="2"><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">Serializability  Annotations ,把Person.java 中的 </font></code></font><code><font size="2"><span style="FONT-FAMILY: 'Courier New',Courier">/<font color="#808000">/@Serializability //测试自定义约束 </font>注释去掉就ok了.</span></font></code></p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">运行结果如下:</span>
						</font>
				</code>
				<font size="2">
						<p align="left">
								<font color="#ff00ff">InvalidValue 的长度是:3 . 验证消息是: </font>
								<font color="#008000">bean must be serialiable</font>
								<font color="#ff00ff"> . PropertyPath 是:null .</font>
						</p>
						<p align="left">
								<font color="#ff00ff">PropertyName 是: null. Value 是: test.annotation.validator.Person@1a73d3c Bean 是: test.annotation.validator.Person@1a73d3c</font>
						</p>
						<p align="left">
								<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
						</p>
				</font>
		</p>
		<p>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">现在把Person类实现 java.io.Serializable 接口 则没有出现 验证错误消息.</span>
						</font>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">消息的国际化也是很简单的,把</span>
				</code>
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#000000">Serializability  中的message 改为以{}扩住的 属性文件的Key就可以了 </font>
						</code>
				</font>
		</p>
		<p align="left">
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#7f0055">
										<b>public </b>
								</font>
								<font color="#000000">@interface Serializability {</font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#7f0055">
										<b>int </b>
								</font>
								<font color="#000000">num() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#990000">11</font>
								<font color="#000000">; </font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#000000">String message() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#2a00ff">"{Serializable}"; </font>
								<font color="#008000">//"bean must be serialiable"; </font>
								<font color="#ff0000">//消息的国际化</font>
								<br />
								<font color="#000000">}</font>
						</code>
				</font>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">然后编辑资料文件. 注意 该资源文件中要包括 Hibernate Validator 内建的资源. 可以在该org\hibernate\validator\resources 包里面的资源文件基础上修改 ,在打包里面 这样就可以了. 自己打包可能不太方便.你可以把该包里面的文件复制出来.然后放到你自己的项目包下在自己编辑, 该测试中 我是放在 test\resources 包下的.</span>
						</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">然后在 资源文件中添加 </span>
						</font>
				</code>
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#2a00ff">Serializable = '''''' </font>这么一行, 样例如下:</code>
				</font>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">#<font color="#ff0000">DefaultValidatorMessages.properties (DefaultValidatorMessages_zh.properties 不再列出^_^)</font></span>
						</font>
				</code>
		</p>
		<p align="left">　</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" color="#ff0000" size="2">#下面是 Hibernate Validator 内建的国际化消息 </font>
				</code>
				<font size="2">
				</font>
		</p>
		<p align="left">
				<font size="2">validator.assertFalse=</font>
				<font color="#2a00ff" size="2">assertion</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">failed</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.assertTrue=</font>
				<font color="#2a00ff" size="2">assertion</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">failed</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.future=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">a</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">future</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">date</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.length=</font>
				<font color="#2a00ff" size="2">length</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">between</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{min}</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">and</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{max}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.max=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">less</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">than</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">or</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">equal</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">to</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{value}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.min=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">greater</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">than</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">or</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">equal</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">to</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{value}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.notNull=</font>
				<font color="#2a00ff" size="2">may</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">not</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">null</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.past=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">a</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">past</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">date</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.pattern=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">match</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">"{regex}"</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.range=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">between</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{min}</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">and</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{max}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.size=</font>
				<font color="#2a00ff" size="2">size</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">between</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{min}</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">and</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{max}</font>
		</p>
		<p align="left">
				<font color="#2a00ff" size="2">#下面是自定义的消息</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">Serializable=</font>
				<font color="#2a00ff" size="2">Bean</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">not</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">Serializable  //加上自己定义的国际化消息. </font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">在构造</span>
						</font>
						<font face="Courier New, Courier" size="2">ClassValidator</font>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier"> 时要添上 资源文件 如下:(在测试类中)</span>
						</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">ClassValidator&lt;Person&gt; classValidator = new ClassValidator&lt;Person&gt; (Person.class,<font color="#ff0000">ResourceBundle.getBundle("</font><font color="#0000ff">test.resources.DefaultValidatorMessages</font><font color="#ff0000">"</font>));//加载资源</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">这样就可以了 .  当然 你还可以 更改 Hibernate Validator 的消息(不是在上面的资源文件中直接修改</font>
				</code>
				<font size="2">validator.length = ... 等等 </font>
				<code>
						<font face="Courier New, Courier" size="2">) , 还记得 Validator 注释中有个 message 元素吗? 你以前用的都是默认值,现在你可以该为你自己定义的了.</font>
				</code>
				<font size="2">如:validator.length 我把他改为 "<font color="#0000ff">该字符串的长度不符合规定范围范围</font>". 在资源文件中添加一行键值属性对(key定义为 "<font color="#ff0000">myMsg</font>")如下:</font>
		</p>
		<p align="left">
				<font size="2">myMsg=<font color="#0000ff">该字符串的长度不符合规定范围范围</font></font>
		</p>
		<p align="left">
				<font size="2">并且还要在</font>
				<font color="#0000ff" size="2">@Length </font>
				<font size="2">注释中提供message的引用的key 如下</font>
				<font color="#0000ff" size="2">@Length(min = 4,message = "{</font>
				<font color="#ff0000" size="2">myMsg</font>
				<font color="#0000ff" size="2">}")</font>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">再一次运行测试 ,我们就可以看到上面两条自定义绑定的消息了 .如下:</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">InvalidValue 的长度是:3 . <font color="#008000">验证消息是</font>: <font color="#ff0000">Bean 不是 可 Serializable</font> . PropertyPath 是:null .<br />PropertyName 是: null. Value 是: test.annotation.validator.Person@1bd4722 Bean 是: test.annotation.validator.Person@1bd4722<br />BeanClass 是:class test.annotation.validator.Person</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier">
								<br />InvalidValue 的长度是:3 . <font color="#008000">验证消息是</font>: <font color="#ff0000">该字符串的长度不符合规定范围范围</font> . PropertyPath 是:name .<br />PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@1bd4722<br />BeanClass 是:class test.annotation.validator.Person</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier">怎么样,比你想象的简单吧. </font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">OK 上面我们讨论了 </font>
				</code>Hibernate Validator 的主要用法: 但是 该框架有什么用呢? ^_^</p>
		<p align="left">看到这里其实不用我在多说了 大家都知道怎么用,什么时候用. 作为一篇介绍性文章我还是在此给出一个最常用的例子吧,更好的使用方式大家慢慢挖掘吧.</p>
		<p align="left">比如 : 你现在在开发一个人力资源(HR)系统 (其实是我们ERP课程的一个作业 ^_^), 里面要处理大量的数据,尤其是在输入各种资料时 如 登记员工信息. 如果你公司的员工的年龄要求是18 -- 60 那么你所输入的年龄就不能超出这个范围. 你可能会说这很容易啊 , 不用Validator就可以解决啊.这保持数据前验证就可以啦 如if ( e.getAge() &gt; 60 || e.getAge() &lt; 18 ) ........ 给出错误信息 然后提示重新输入不就OK啦 用得着 兴师动众的来个第三方框架吗? </p>
		<p align="left">是啊 当就验证这一个属性时, 没有必要啊 ! 但是一个真正的HR 系统,会只有一个属性要验证吗? 恐怕要有N多吧</p>
		<p align="left">你要是每一个都那样 写一段验证代码 是不是很烦啊 ,况且也不方便代码重用. 现在考虑一些 Validator 是不是更高效啊,拦截到 约束违例的 属性 就可以直接得到 国际化的消息 可以把该消息显示到一个弹出对话框上 提示更正  !</p>
		<p align="left">Validator的用处不只这一种 ,你可以想到如何用呢 ! 欢迎发表你的高见!!</p>
		<p align="left">OK 到此 我们的 Hibernate Validator 之旅就要先告一段落了 . 希望这是令你心旷神怡的一次寒冬之旅,</p>
		<p align="left">把你学到的应用到你的项目中吧,一定会提高你的生产率的. 相信我 ,没错的  ^_^ !</p>
<img src ="http://www.blogjava.net/lijiajia418/aggbug/67094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-09-01 14:05 <a href="http://www.blogjava.net/lijiajia418/archive/2006/09/01/67094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate Annotations 实战(二)</title><link>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67093.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Fri, 01 Sep 2006 06:04:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67093.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/67093.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67093.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/67093.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/67093.html</trackback:ping><description><![CDATA[
		<a>-- hbm.xml 与 Annotations 性能比较</a>
		<p align="left">
				<span style="COLOR: red">任何获得Matrix授权的网站，转载请保留以下作者信息和链接：</span>
				<br />作者：icess(作者的blog:<a href="http://blog.matrix.org.cn/page/icess" target="_new">http://blog.matrix.org.cn/page/icess</a>)<br />关键字：Hibernate Validator</p>
		<p align="left">我在前面一篇文章&lt;<a href="http://www.matrix.org.cn/resource/article/44/44141_Hibernate_Annotations.html">Hibernate Annotations 实战-- 从 hbm.xml 到 Annotations</a>&gt;:</p>
		<p align="left">中,有很多开发者在谈论中提到,有没有必要从 hbm.xml 往 Annotations 上转移. 那么在这篇文章中我们就来讨论一下 hbm.xml 与 Annotations的优缺点,看看那种情况最适合你.</p>
		<p align="left">首先,讨论一下 xml 配置文件的优点, 个人认为主要优点就是当你改变底层配置时 不需要改变和重新编译代码,只需要在xml 中更改就可以了,例如 Hibernate.cfg.xml 当你要更改底层数据库时, 只要更改配置文件就可以了.Hibernate会为你做好别的事情.</p>
		<p align="left">那么xml的缺点呢,个人认为有以下几点:</p>
		<div id="bodyColumn">
				<div class="contentBox">
						<div class="section">
								<ul>
										<li>
												<p align="left">描述符多，不容易记忆,掌握 要深入了解还有看DTD文件 </p>
										</li>
										<li>
												<p align="left">无法做自动校验，需要人工查找 </p>
										</li>
										<li>
												<p align="left">读取和解析xml配置要消耗一定时间，导致应用启动慢，不便于测试和维护 </p>
										</li>
										<li>
												<p align="left">当系统很大时，大量的xml文件难以管理 </p>
										</li>
										<li>
												<p align="left">运行中保存xml配置需要消耗额外的内存 </p>
										</li>
										<li>
												<p align="left">在O/R Mapping的时候需要在java文件和xml配置文件之间交替，增大了工作量 </p>
										</li>
								</ul>
								<p align="left">其中第一 二点 借助于先进的IDE 可能不是什么问题. 但是对初学者还是个问题 ^_^.</p>
						</div>
				</div>
		</div>　 
<p align="left">下面我们看看 Annotations的 特性吧! 可以解决xml遇到的问题,有以下优点</p><div id="bodyColumn0"><div class="contentBox"><div class="section"><ul><li><p align="left">描述符减少。以前在xml配置中往往需要描述java属性的类型，关系等等。而元数据本身就是java语言，从而省略了大量的描述符 </p></li><li><p align="left">编译期校验。错误的批注在编译期间就会报错。 </p></li><li><p align="left">元数据批注在java代码中，避免了额外的文件维护工作 </p></li><li><p align="left">元数据被编译成java bytecode，消耗的内存少，读取也很快，利于测试和维护 </p></li></ul><p align="left">关于 映射文件是使用 hbm.xml 文件还是使用 Annotations 我们来看看2者的性能吧. 先声明一下,个人认为映射文件一旦配置好就不会在很大程度上改变了.所以使用xml文件并不会带来很大的好处.如果你认为 映射文件在你的项目中也经常变化,比如一列String数据 ,今天你使用 <font color="#7f007f" size="2">length</font><font size="2">=</font><font color="#2a00ff" size="2">"16"</font><font size="2"> 明天你认为 该数据的长度应该更长才能满足业务需求 于是改为</font><font color="#7f007f" size="2">length</font><font size="2">=</font><font color="#2a00ff" size="2">"128"</font> 等等类似的问题 . 如果你经常有这方面的变动的话,下面的比较你可以不用看了 , 你应该使用 xml文件 因为Annotations 无法很好的满足你的要求.</p><p align="left">现在让我们就来看看2者的性能比较吧.</p><p align="left">(说明: 这里只是比较查找 插入 的时间快慢,没有比较除运行时间以外的其他性能,如 内存占用量 等等)</p><p align="left">先来看看测试程序和配置.</p><p align="left">首先在 Hibernate.cfg.xml 文件中去掉了 </p><font color="#008080" size="2"></font><p align="left"><font color="#008080" size="2">&lt;</font><font color="#3f7f7f" size="2">property </font><font color="#7f007f" size="2">name</font><font size="2">=</font><font color="#2a00ff" size="2">"hibernate.hbm2ddl.auto"</font><font color="#008080" size="2">&gt;</font><font size="2">update</font><font color="#008080" size="2">&lt;/</font><font color="#3f7f7f" size="2">property</font><font color="#008080" size="2">&gt;</font></p></div></div></div><p align="left">这一行, 因为在前面的实验中以及建立了数据库表了 不再需要更新了.如果你是第一次运行该例子 还是要该行的.</p><p align="left">Test.java 如下:</p><p align="left"><code><font color="#3f7f5f">/*</font><br /><font color="#ffffff"> </font><font color="#3f7f5f">* Created on 2005</font><br /><font color="#ffffff"> </font><font color="#3f7f5f">* @author </font><br /><font color="#ffffff"> </font><font color="#3f7f5f">*/</font><br /><font color="#7f0055"><b>package </b></font><font color="#000000">test.hibernate.annotation;</font><br /><br /><font color="#7f0055"><b>import </b></font><font color="#000000">org.hibernate.Session;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">org.hibernate.Transaction;</font><br /><br /><font color="#7f0055"><b>public class </b></font><font color="#000000">Test {</font><br /><font color="#ffffff">  </font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public static void </b></font><font color="#000000">main(String [] args) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>long </b></font><font color="#000000">start = </font><font color="#990000">0</font><font color="#000000">;</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>long </b></font><font color="#000000">end = </font><font color="#990000">0</font><font color="#000000">;</font><br /><font color="#ffffff">    </font><font color="#000000">start = System.currentTimeMillis();  </font><font color="#3f7f5f">//程序开始时间</font><br /><font color="#ffffff">    </font><br /><font color="#ffffff">    </font><font color="#000000">Session s = HibernateUtil.currentSession();</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>long </b></font><font color="#000000">mid =  System.currentTimeMillis();  </font><font color="#3f7f5f">//</font><font color="#3f7f5f">初始化完毕的时间 (可能此时并没有初始化完毕^_^)</font><br /><font color="#ffffff">    </font><br /><font color="#ffffff">    </font><font color="#000000">Transaction tx = s.beginTransaction();    </font><br /><font color="#ffffff">    </font><font color="#3f5fbf">/********************测试读取的代码************************/</font><br /><font color="#ffffff">    </font><font color="#000000">Person p = </font><font color="#7f0055"><b>null</b></font><font color="#000000">;</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>for</b></font><font color="#000000">(</font><font color="#7f0055"><b>int </b></font><font color="#000000">i = </font><font color="#990000">1</font><font color="#000000">; i &lt;= </font><font color="#990000">100</font><font color="#000000">; i ++) {</font><br /><font color="#ffffff">    </font><font color="#000000">p = (Person) s.get(Person.class, i);</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(p.getName());</font><br /><font color="#ffffff">    </font><font color="#000000">}</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(p.getName());</font></code></p><p align="left"><code><font color="#3f5fbf">    /********************测试读取1次的代码************************/</font><br /><font color="#ffffff">    </font><font color="#000000">Person p = </font><font color="#7f0055"><b>null</b></font><font color="#000000">;</font><br /><font color="#ffffff">    </font><font color="#000000">p = (Person) s.get(Person.class, 1);</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(p.getName());</font><br /><font color="#ffffff">    </font><font color="#3f5fbf">/*********************测试插入的代码*************************************/</font><br /><font color="#ffffff">    </font><font color="#3f7f5f">/*</font><br /><font color="#ffffff">    </font><font color="#3f7f5f">for (int i = 0; i &lt; 100; i ++) {</font><br /><font color="#ffffff">      </font><font color="#3f7f5f">Person p = new Person();</font><br /><font color="#ffffff">      </font><font color="#3f7f5f">p.setAge(i+1);</font><br /><font color="#ffffff">      </font><font color="#3f7f5f">p.setName("icerain"+i);</font><br /><font color="#ffffff">      </font><font color="#3f7f5f">p.setSex("male"+i);</font><br /><font color="#ffffff">      </font><font color="#3f7f5f">s.save(p);</font><br /><font color="#ffffff">      </font><font color="#3f7f5f">s.flush();</font><br /><font color="#ffffff">    </font><font color="#3f7f5f">}</font><br /><font color="#ffffff">    </font><font color="#3f7f5f">*/</font><br /><font color="#ffffff">    </font><font color="#000000">tx.commit();</font><br /><font color="#ffffff">    </font><font color="#000000">HibernateUtil.closeSession();</font><br /><font color="#ffffff">    </font><br /><font color="#ffffff">    </font><font color="#000000">end = System.currentTimeMillis(); </font><font color="#3f7f5f">//</font><font color="#3f7f5f">测试结束时间</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(</font><font color="#2a00ff">"String[] - start time: " </font><font color="#000000">+ start);</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(</font><font color="#2a00ff">"String[] - end time: " </font><font color="#000000">+ end);</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(</font><font color="#2a00ff">"Init time : " </font><font color="#000000">+ (mid-start)); </font><font color="#008000">// 打印初始化用的时间</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(</font><font color="#2a00ff">"Last time is :" </font><font color="#000000">+(end - mid) ); </font><font color="#008000">//打印 数据操作的时间</font><br /><font color="#ffffff">    </font><font color="#000000">System.out.println(</font><font color="#2a00ff">"Total time : " </font><font color="#000000">+(end - start)); </font><font color="#008000">//打印总时间<br /> </font> }<br /><font color="#000000">}</font></code></p><p align="left">Annotations 包中的Person.java 如下</p><p align="left"><code><font color="#7f0055"><b>package </b></font><font color="#000000">test.hibernate.annotation;</font><br /><br /><font color="#7f0055"><b>import </b></font><font color="#000000">java.util.LinkedList;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">java.util.List;</font><br /><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.AccessType;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.Basic;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.Entity;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.GeneratorType;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.Id;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.Table;</font><br /><font color="#7f0055"><b>import </b></font><font color="#000000">javax.persistence.Transient;</font><br /><br /><font color="#3f5fbf">/**</font><br /><font color="#ffffff"> </font><font color="#3f5fbf">* Person generated by hbm2java</font><br /><font color="#ffffff"> </font><font color="#3f5fbf">*/</font><br /><br /><font color="#000000">@SuppressWarnings(</font><font color="#2a00ff">"serial"</font><font color="#000000">)</font><br /><font color="#000000">@Entity(access = AccessType.PROPERTY)</font><br /><font color="#000000">@Table</font><br /><font color="#7f0055"><b>public class </b></font><font color="#000000">Person </font><font color="#7f0055"><b>implements </b></font><font color="#000000">java.io.Serializable {</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>private </b></font><font color="#000000">Integer id;</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>private </b></font><font color="#000000">String name;</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>private </b></font><font color="#000000">String sex;</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>private </b></font><font color="#000000">Integer age;</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>private </b></font><font color="#000000">List list = </font><font color="#7f0055"><b>new </b></font><font color="#000000">LinkedList();</font><br /><br /><font color="#ffffff">  </font><font color="#3f7f5f">// Constructors</font><br /><font color="#ffffff">  </font><font color="#3f5fbf">/** default constructor */</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">Person() {</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#3f5fbf">/** constructor with id */</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">Person(Integer id) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>this</b></font><font color="#000000">.id = id;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#3f7f5f">// Property accessors</font><br /><font color="#ffffff">  </font><font color="#000000">@Id(generate=GeneratorType.AUTO)</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">Integer getId() {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>return this</b></font><font color="#000000">.id;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">setId(Integer id) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>this</b></font><font color="#000000">.id = id;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#000000">@Basic</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">String getName() {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>return this</b></font><font color="#000000">.name;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">setName(String name) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>this</b></font><font color="#000000">.name = name;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#000000">@Basic</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">String getSex() {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>return this</b></font><font color="#000000">.sex;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">setSex(String sex) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>this</b></font><font color="#000000">.sex = sex;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#000000">@Basic</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">Integer getAge() {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>return this</b></font><font color="#000000">.age;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">setAge(Integer age) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>this</b></font><font color="#000000">.age = age;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><font color="#ffffff">  </font><font color="#000000">@Transient</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public </b></font><font color="#000000">List getList() {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>return </b></font><font color="#000000">list;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">setList(List list) {</font><br /><font color="#ffffff">    </font><font color="#7f0055"><b>this</b></font><font color="#000000">.list = list;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#000000">}</font></code></p><p align="left">其他的代码几乎没有改变:</p><p align="left">下面的每种类型的测试都测试了3次以上, 取中间的测试时间.</p><p align="left">测试机器配置:</p><p align="left">CPU:  AMD Athlon (xp) 2000+</p><p align="left">内存: 784880KB</p><p align="left">硬盘: 三星 SP0812N</p><p align="left">读取一次  的比较:(单位: 毫秒)</p><table id="table4" width="100%" border="1"><tbody><tr><td colspan="2">使用Annotations 的测试数据</td><td width="24%" colspan="2">使用Xml文件的测试数据</td><td width="46%">简要说明</td></tr><tr><td width="15%">Init time : </td><td width="12%">2444</td><td width="16%">Init time : </td><td width="8%">2431</td><td width="46%">测试前我认为该项结果xml应该比较大,要读取映射文件啊,实际情况不是这样,不知道为什么?</td></tr><tr><td width="15%">Last time is :</td><td width="12%"><font color="#ff00ff">62</font></td><td width="16%">Last time is :</td><td width="8%"><font color="#ff0000">85</font></td><td width="46%">相差比较大不知道为什么?</td></tr><tr><td width="15%">Total time : </td><td width="12%">2506</td><td width="16%">Total time : </td><td width="8%">2516</td><td width="46%">xml文件总体上慢了一点</td></tr></tbody></table><p>   读取100次的比较:</p><table id="table5" width="100%" border="1"><tbody><tr><td colspan="2">使用Annotations 的测试数据</td><td width="29%" colspan="2">使用Xml文件的测试数据</td><td width="42%">简要说明</td></tr><tr><td width="15%">Init time : </td><td width="12%">2437</td><td width="16%">Init time : </td><td width="11%">2422</td><td width="42%">和前面初始化差不多</td></tr><tr><td width="15%">Last time is :</td><td width="12%"><font color="#ff00ff">438</font></td><td width="16%">Last time is :</td><td width="11%"><font color="#ff0000">484</font></td><td width="42%">有时间差</td></tr><tr><td width="15%">Total time : </td><td width="12%">2875</td><td width="16%">Total time : </td><td width="11%">2906</td><td width="42%">也是xml文件总体上慢了一点</td></tr></tbody></table><p>插入100次的比较:</p><table id="table6" width="100%" border="1"><tbody><tr><td colspan="2">使用Annotations 的测试数据</td><td width="29%" colspan="2">使用Xml文件的测试数据</td><td width="42%">简要说明</td></tr><tr><td width="15%">Init time : </td><td width="12%">2453</td><td width="16%">Init time : </td><td width="11%">2469</td><td width="42%">和前面初始化差不多</td></tr><tr><td width="15%">Last time is :</td><td width="12%"><font color="#ff00ff">469</font></td><td width="16%">Last time is :</td><td width="11%"><font color="#ff0000">656</font></td><td width="42%">有时间差</td></tr><tr><td width="15%">Total time : </td><td width="12%">2922</td><td width="16%">Total time : </td><td width="11%">3125</td><td width="42%">也是xml文件总体上慢了一点</td></tr></tbody></table><p>从上面的三次对比中大家可以看到 初始化的部分几乎两者是一样的, 在数据操作上面 使用xml文件 总是比使用Annotations 慢一点.在我们只操纵一个只有几个属性的小持久化类的操作中就有 几十毫秒的差距. 几十毫秒在计算机中算不算很大 大家应该都知道,我就不在多说了.</p><p>总结: 经过 xml 文件 和Annotations 的优缺点和 性能上的对比.现在使用那个作为你持久化映射策略.我相信大家都会正确选择的.</p><p>测试后记: 经过多次测试 感觉有时候很不稳定 ,有的时候很稳定不知道是测试有问题还是别的问题.大家可以自己测试一下. 有什么新的发现 请大家讨论讨论.</p><img src ="http://www.blogjava.net/lijiajia418/aggbug/67093.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-09-01 14:04 <a href="http://www.blogjava.net/lijiajia418/archive/2006/09/01/67093.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第一个Hibernate with Annotation程式</title><link>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67092.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Fri, 01 Sep 2006 06:00:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67092.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/67092.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/67092.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/67092.html</trackback:ping><description><![CDATA[
		<a>
				<font size="5">H</font>ibernate是ORM的解决方案，其底层对数据库的操作依赖于JDBC，所以您必须先取得JDBC驱动程序，在这边所使用的是MySQL，所以您必须至 MySQL® Connector/J 取得MySQL的JDBC驱动程序。 <br /><br />接下来至 </a>
		<a href="http://www.hibernate.org/">Hibernate 官方网站</a> 取得<span style="COLOR: rgb(255,0,0)">Hibernate 3.2</span>、<span style="COLOR: rgb(255,0,0)">Hibernate Annotations 3.2</span>。 <br /><br />您必须<span style="COLOR: rgb(255,0,0)">安装JDK 5.0</span>才可以使用Hibernate Annotations的功能。 <br /><br />解开Hibernate 3.2的zip档案后，当中的hibernate3.jar是必要的，而在lib目录中还包括了许多jar档案，您可以在 Hibernate 3.0官方的参考手册 上找到这些jar的相关说明，其中必要的是 antlr、dom4j、CGLIB、asm、Commons Collections、Commons Logging、 EHCache，Hibernate底层还需要Java Transaction API，所以您还需要jta.jar。 <br /><br />解开Hibernate Annotations 3.2的zip档案后，您需要hibernate-annotations.jar、ejb3-persistence.jar这两个档案。 <br /><br />到这边为止，总共需要以下的jar档案：<br /><a href="http://p.blog.csdn.net/images/p_blog_csdn_net/caterpillar_here/1152886204259.jpg" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/caterpillar_here/1152886204259.jpg" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><br />Hibernate可以运行于单机之上，也可以运行于Web应用程序之中，如果是运行于单机，则将所有用到的jar档案（包括JDBC驱动程序）设定至CLASSPATH中，如果是运行于Web应用程序中，则将jar档案置放于WEB-INF/lib中。<br /><br />如果您还需要额外的Library，再依需求加入，例如JUnit、Proxool等等，接下来可以将etc目录下的 log4j.properties复制至Hibernate项目的Classpath下，并修改一下当中的 log4j.logger.org.hibernate为error，也就是只在在错误发生时显示必要的讯息。<br /><br />接着设置基本的Hibernate配置文件，可以使用XML或Properties档案，这边先使用XML，档名预设为hibernate.cfg.xml：<br /><br /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">&lt;?xml version="1.0" encoding="utf-8"?&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">&lt;!DOCTYPE hibernate-configuration PUBLIC</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">&lt;hibernate-configuration&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    &lt;session-factory&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- 显示实际操作数据库时的SQL --&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;property name="show_sql"&gt;true&lt;/property&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- SQL方言，这边设定的是MySQL --&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;property name="dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/property&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- JDBC驱动程序 --&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;property name="connection.driver_class"&gt;com.mysql.jdbc.Driver&lt;/property&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- JDBC URL --&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;property name="connection.url"&gt;jdbc:mysql://localhost/demo&lt;/property&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- 数据库使用者 --&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;property name="connection.username"&gt;root&lt;/property&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- 数据库密码 --&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;property name="connection.password"&gt;123456&lt;/property&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;!-- 以下设置对象与数据库表格映像类别 --&gt;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        &lt;mapping class="onlyfun.caterpillar.User"/&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    &lt;/session-factory&gt; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">&lt;/hibernate-configuration&gt;</span><br /><br />这边以一个简单的单机程序来示范Hibernate的配置与功能，首先作数据库的准备工作，在MySQL中新增一个demo数据库，并建立user表格：<span class="javascript" id="text160062" style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"><pre>CREATE TABLE user (<br />    id INT(11) NOT NULL auto_increment PRIMARY KEY,<br />    name VARCHAR(100) NOT NULL <font class="java-reserved_word">default</font><font class="java-string">''</font>,<br />    age INT<br />);</pre></span><font face="宋体, MS Song">对于这个表格，您有一个User类别与之对应，表格中的每一个字段将对应至User实例上的Field成员。<br /><br /></font><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">package onlyfun.caterpillar;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">import javax.persistence.*;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">@Entity</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">@Table(name="user") // 非必要，在表格名称与类别名称不同时使用</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">public class User {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  @Id</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  @GeneratedValue(strategy=GenerationType.AUTO)</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    private Integer id;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  @Column(name="name") // 非必要，在字段名称与属性名称不同时使用</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    private String name;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">  @Column(name="age") </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    private Integer age; // 非必要，在字段名称与属性名称不同时使用</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    // 必须要有一个预设的建构方法</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    // 以使得Hibernate可以使用Constructor.newInstance()建立对象</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public User() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public Integer getId() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        return id;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public void setId(Integer id) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        this.id = id;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public String getName() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        return name;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public void setName(String name) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        this.name = name;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public Integer getAge() {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        return age;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public void setAge(Integer age) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        this.age = age;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">}</span><br /><br /><font face="宋体, MS Song">其中id是个特殊的属性，Hibernate会使用它来作为主键识别，您可以定义主键产生的方式，这边设定为自动产生主键，可以看到，实体标识，主键生成，以及相关映像，都可以使用Annotation来完成。 <br /><br />接下来撰写一个测试的程序，这个程序直接以Java程序设计人员熟悉的语法方式来操作对象，而实际上也直接完成对数据库的操作，程序将会将一笔数据存入表格之中：<br /></font><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">package onlyfun.caterpillar;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">import org.hibernate.SessionFactory;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">import org.hibernate.Session;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">import org.hibernate.Transaction; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">import org.hibernate.cfg.AnnotationConfiguration;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">import org.hibernate.cfg.Configuration; </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">public class HibernateAnnotationDemo {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    public static void main(String[] args) {</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // 需要AnnotationConfiguration读取Annotation讯息</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        Configuration config = new AnnotationConfiguration().configure();</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // 根据 config 建立 SessionFactory</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // SessionFactory 将用于建立 Session</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        SessionFactory sessionFactory = config.buildSessionFactory(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // 将持久化的物件</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        User user = new User(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        user.setName("caterpillar"); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        user.setAge(new Integer(30));     </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New"> </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // 开启Session，相当于开启JDBC的Connection</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        Session session = sessionFactory.openSession(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // Transaction表示一组会话操作</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        Transaction tx= session.beginTransaction(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        // 将对象映像至数据库表格中储存</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        session.save(user); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        tx.commit(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        session.close(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        sessionFactory.close(); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">       </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">        System.out.println("新增资料OK!请先用MySQL观看结果！"); </span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">    }</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">}</span><br /><br /><font face="宋体, MS Song">注意，使用Annotation时，需要的是AnnotationConfiguration类别。 <br /><br />如您所看到的，程序中只需要直接操作User对象，并进行Session与Transaction的相关操作，Hibernate就会自动完成对数据库的操作，您看不到任何一行JDBC或SQL的陈述，撰写好以上的各个档案之后，各档案的放置位置如下：<br /></font><a href="http://p.blog.csdn.net/images/p_blog_csdn_net/caterpillar_here/1152886574068.jpg" target="_blank"><font face="宋体, MS Song"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" style="ZOOM: 100%" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/caterpillar_here/1152886574068.jpg" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></font></a><br /><br /><font face="宋体, MS Song">接着可以开始运行程序，结果如下：<br /></font><div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">Hibernate: insert into user (name, age) values (?, ?)</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">新增资料OK!请先用MySQL观看结果！</span><br /></div><br />执行结果中显示了Hibernate所实际使用的SQL，由于这个程序还没有查询功能，所以要进入MySQL中看看新增的数据，如下：<br /><div style="MARGIN-LEFT: 40px"><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">mysql&gt; select * from user;</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">+----+-----------------+------+</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">| id    | name         | age  |</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">+----+-----------------+------+</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">|  1    | caterpillar  | 30   |</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">+----+-----------------+------+</span><br style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New" /><span style="FONT-WEIGHT: bold; FONT-FAMILY: Courier New">1 row in set (0.03 sec)</span><br /></div><img src ="http://www.blogjava.net/lijiajia418/aggbug/67092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-09-01 14:00 <a href="http://www.blogjava.net/lijiajia418/archive/2006/09/01/67092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate Annotations 实战</title><link>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67090.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Fri, 01 Sep 2006 05:59:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67090.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/67090.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/67090.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/67090.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 任何获得Matrix授权的网站，转载请保留以下作者信息和链接：				作者：icess(作者的blog:http://blog.matrix.org.cn/page/icess)关键字：Hibernate Validator		下面让我们先看一个通常用 hbm.xml 映射文件的例子. 有3个类 .HibernateUtil.java 也就是 Hibernate文档中推荐的工具类,Pers...&nbsp;&nbsp;<a href='http://www.blogjava.net/lijiajia418/archive/2006/09/01/67090.html'>阅读全文</a><img src ="http://www.blogjava.net/lijiajia418/aggbug/67090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-09-01 13:59 <a href="http://www.blogjava.net/lijiajia418/archive/2006/09/01/67090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在filter中關閉session</title><link>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67085.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Fri, 01 Sep 2006 05:51:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67085.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/67085.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/09/01/67085.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/67085.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/67085.html</trackback:ping><description><![CDATA[
		<p>利用<a title="Thread-Specific Storage" href="http://www.javaworld.com.tw/confluence/display/designpattern/Thread-Specific+Storage">Thread-Specific Storage</a>撰寫一個HibernateUtil</p>
		<div class="code" style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
				<div class="codeHeader" style="BORDER-BOTTOM-STYLE: solid">
						<b>HibernateSessionUtil.java</b>
				</div>
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-keyword">import</span> java.io.Serializable;<br /><br /><span class="code-keyword">import</span> net.sf.hibernate.HibernateException;<br /><span class="code-keyword">import</span> net.sf.hibernate.Session;<br /><span class="code-keyword">import</span> net.sf.hibernate.SessionFactory;<br /><span class="code-keyword">import</span> net.sf.hibernate.Transaction;<br /><br /><span class="code-keyword">public</span> class HibernateSessionUtil <span class="code-keyword">implements</span> Serializable<br />{<br /><span class="code-keyword">public</span><span class="code-keyword">static</span><span class="code-keyword">final</span> ThreadLocal tLocalsess = <span class="code-keyword">new</span> ThreadLocal();<br /><br /><span class="code-keyword">public</span><span class="code-keyword">static</span><span class="code-keyword">final</span> ThreadLocal tLocaltx = <span class="code-keyword">new</span> ThreadLocal();<br /><br />    /*<br />     * getting the thread-safe session <span class="code-keyword">for</span> using<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> Session currentSession(){<br />        Session session = (Session) tLocalsess.get();<br /><br /><span class="code-comment">//open a <span class="code-keyword">new</span> one, <span class="code-keyword">if</span> none can be found.<br /></span><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (session == <span class="code-keyword">null</span>){<br />                session = openSession();<br />                tLocalsess.set(session);<br />            }<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br /><span class="code-keyword">return</span> session;<br />    }<br /><br />    /*<br />     * closing the thread-safe session<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void closeSession(){<br /><br />        Session session = (Session) tLocalsess.get();<br />        tLocalsess.set(<span class="code-keyword">null</span>);<br /><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (session != <span class="code-keyword">null</span> &amp;&amp; session.isOpen()){<br />                session.close();<br />            }<br /><br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br />    /*<br />     * begin the transaction<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void beginTransaction(){<br />        Transaction tx = (Transaction) tLocaltx.get();<br /><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (tx == <span class="code-keyword">null</span>){<br />                tx = currentSession().beginTransaction();<br />                tLocaltx.set(tx);<br />            }<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br />    /*<br />     * close the transaction<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void commitTransaction(){<br />        Transaction tx = (Transaction) tLocaltx.get();<br /><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (tx != <span class="code-keyword">null</span> &amp;&amp; !tx.wasCommitted() &amp;&amp; !tx.wasRolledBack())<br />                tx.commit();<br />            tLocaltx.set(<span class="code-keyword">null</span>);<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br />    /*<br />     * <span class="code-keyword">for</span> rollbacking<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void rollbackTransaction(){<br />        Transaction tx = (Transaction) tLocaltx.get();<br /><span class="code-keyword">try</span>{<br />            tLocaltx.set(<span class="code-keyword">null</span>);<br /><span class="code-keyword">if</span> (tx != <span class="code-keyword">null</span> &amp;&amp; !tx.wasCommitted() &amp;&amp; !tx.wasRolledBack()){<br />                tx.rollback();<br />            }<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br /><span class="code-keyword">private</span><span class="code-keyword">static</span> Session openSession() <span class="code-keyword">throws</span> HibernateException{<br /><span class="code-keyword">return</span> getSessionFactory().openSession();<br />    }<br /><br /><span class="code-keyword">private</span><span class="code-keyword">static</span> SessionFactory getSessionFactory() <span class="code-keyword">throws</span> HibernateException{<br /><span class="code-keyword">return</span> SingletonSessionFactory.getInstance();<br />    }<br />}</pre>
				</div>
		</div>
		<p>　filter中的程式碼如下</p>
		<div class="code" style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
				<div class="codeHeader" style="BORDER-BOTTOM-STYLE: solid">
						<b>HibernateSessionCloser.java</b>
				</div>
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-keyword">public</span> class HibernateSessionCloser <span class="code-keyword">implements</span> Filter{<br /><br /><span class="code-keyword">protected</span> FilterConfig filterConfig = <span class="code-keyword">null</span>;<br /><br /><span class="code-keyword">public</span> void init(FilterConfig filterConfig)<span class="code-keyword">throws</span> ServletException{<br /><span class="code-keyword">this</span>.filterConfig = filterConfig;<br />    }<br /><br /><span class="code-keyword">public</span> void destroy(){<br /><span class="code-keyword">this</span>.filterConfig = <span class="code-keyword">null</span>;<br />    }    <br /><br /><span class="code-keyword">public</span> void doFilter(ServletRequest request, ServletResponse response,<br />                         FilterChain chain)<br /><span class="code-keyword">throws</span> IOException, ServletException {<br /><span class="code-keyword">try</span>{<br />            chain.doFilter(request, response);<br />        }<br /><span class="code-keyword">finally</span>{<br /><span class="code-keyword">try</span>{<br />                HibernateSessionUtil.commitTransaction();<br />            }<span class="code-keyword">catch</span> (InfrastructureException e){<br />                HibernateSessionUtil.rollbackTransaction();<br />            }<span class="code-keyword">finally</span>{<br />                HibernateSessionUtil.closeSession();<br />            }   <br />        }<br /><br />    }<br />}</pre>
				</div>
		</div>
		<p>然後在操作資料庫之前加上</p>
		<div class="code" style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
				<div class="codeContent">
						<pre class="code-java">HibernateSessionUtil.beginTransaction();<br />HibernateSessionUtil.currentSession();<span class="code-comment">//取得Session</span></pre>
				</div>
		</div>
<img src ="http://www.blogjava.net/lijiajia418/aggbug/67085.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-09-01 13:51 <a href="http://www.blogjava.net/lijiajia418/archive/2006/09/01/67085.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 延迟初始化错误（ERROR LazyInitializer）是如何产生的?</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/24/65532.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Thu, 24 Aug 2006 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/24/65532.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65532.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/24/65532.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65532.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65532.html</trackback:ping><description><![CDATA[
		<a>摘要：<br />延迟初始化错误是运用Hibernate开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略，那么必须当代理类实例或代理集合处于持久化状态（即处于Session范围内）时，才能初始化它。如果在游离状态时才初始化它，就会产生延迟初始化错误。<br /><br />延迟初始化错误（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的更多知识，请参考：</a>
		<a title="http://cglib.sourceforge.net/。" href="http://cglib.sourceforge.net/%E3%80%82" target="_blank">http://cglib.sourceforge.net/。 <a href="http://www.jeedev.com/blog/images/link.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" src="http://www.jeedev.com/blog/images/link.gif" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></a>
		<br />以下代码先通过Session的load()方法加载Customer对象，然后访问它的name属性： 
<div class="code">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />customer.getName();tx.commit();</div><br />在运行session.load()方法时Hibernate不执行任何select语句，仅仅返回Customer类的代理类的实例，它的OID为1，这是由load()方法的第二个参数指定的。当应用程序调用customer.getName()方法时，Hibernate会初始化Customer代理类实例，从数据库中加载Customer对象的数据，执行以下select语句：<br /><div class="code">select * from CUSTOMERS where ID=1;select * from ORDERS where CUSTOMER_ID=1;</div><br />当&lt;class&gt;元素的lazy属性为true，会影响Session的load()方法的各种运行时行为，下面举例说明。<br /><br />1．如果加载的Customer对象在数据库中不存在，Session的load()方法不会抛出异常，只有当运行customer.getName()方法时才会抛出以下异常： 
<div class="code">ERROR LazyInitializer:63 - Exception initializing proxynet.sf.hibernate.ObjectNotFoundException: No row with the given identifier exists: 1, of class: mypack.Customer</div><br />2．如果在整个Session范围内，应用程序没有访问过Customer对象，那么Customer代理类的实例一直不会被初始化，Hibernate不会执行任何select语句。以下代码试图在关闭Session后访问Customer游离对象： 
<div class="code">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />tx.commit();<br />session.close();<br />customer.getName();</div><br />由于引用变量customer引用的Customer代理类的实例在Session范围内始终没有被初始化，因此在执行customer.getName()方法时，Hibernate会抛出以下异常： 
<div class="code">ERROR LazyInitializer:63 - Exception initializing proxynet.sf.hibernate.HibernateException: <br />Could not initialize proxy - the owning Session was closed</div>由此可见，Customer代理类的实例只有在当前Session范围内才能被初始化。<br /><br />3．net.sf.hibernate.Hibernate类的initialize()静态方法用于在Session范围内显式初始化代理类实例，isInitialized()方法用于判断代理类实例是否已经被初始化。例如： 
<div class="code">tx = session.beginTransaction();<br />Customer customer=(Customer)session.load(Customer.class,new Long(1));<br />if(!Hibernate.isInitialized(customer)) Hibernate.initialize(customer);<br />tx.commit();<br />session.close();<br />customer.getName();</div>以上代码在Session范围内通过Hibernate类的initialize()方法显式初始化了Customer代理类实例，因此当Session关闭后，可以正常访问Customer游离对象。<br /><br />4．当应用程序访问代理类实例的getId()方法时，不会触发Hibernate初始化代理类实例的行为，例如： 
<div class="code">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();</div>当应用程序访问customer.getId()方法时，该方法直接返回Customer代理类实例的OID值，无需查询数据库。由于引用变量 customer始终引用的是没有被初始化的Customer代理类实例，因此当Session关闭后再执行customer.getName()方法， Hibernate会抛出以下异常：<br /><div class="code">ERROR LazyInitializer:63 - Exception initializing proxynet.sf.hibernate.HibernateException: <br />Could not initialize proxy - the owning Session was closed</div><img src ="http://www.blogjava.net/lijiajia418/aggbug/65532.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-24 15:25 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/24/65532.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在filter中關閉session</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/24/65531.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Thu, 24 Aug 2006 07:24:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/24/65531.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65531.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/24/65531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65531.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65531.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<p>利用<a title="Thread-Specific Storage" href="http://www.javaworld.com.tw/confluence/display/designpattern/Thread-Specific+Storage">Thread-Specific Storage</a>撰寫一個HibernateUtil</p>
										<div class="code" style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
												<div class="codeHeader" style="BORDER-BOTTOM-STYLE: solid">
														<b>HibernateSessionUtil.java</b>
												</div>
												<div class="codeContent">
														<pre class="code-java">
																<span class="code-keyword">import</span> java.io.Serializable;<br /><br /><span class="code-keyword">import</span> net.sf.hibernate.HibernateException;<br /><span class="code-keyword">import</span> net.sf.hibernate.Session;<br /><span class="code-keyword">import</span> net.sf.hibernate.SessionFactory;<br /><span class="code-keyword">import</span> net.sf.hibernate.Transaction;<br /><br /><span class="code-keyword">public</span> class HibernateSessionUtil <span class="code-keyword">implements</span> Serializable<br />{<br /><span class="code-keyword">public</span><span class="code-keyword">static</span><span class="code-keyword">final</span> ThreadLocal tLocalsess = <span class="code-keyword">new</span> ThreadLocal();<br /><br /><span class="code-keyword">public</span><span class="code-keyword">static</span><span class="code-keyword">final</span> ThreadLocal tLocaltx = <span class="code-keyword">new</span> ThreadLocal();<br /><br />    /*<br />     * getting the thread-safe session <span class="code-keyword">for</span> using<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> Session currentSession(){<br />        Session session = (Session) tLocalsess.get();<br /><br /><span class="code-comment">//open a <span class="code-keyword">new</span> one, <span class="code-keyword">if</span> none can be found.<br /></span><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (session == <span class="code-keyword">null</span>){<br />                session = openSession();<br />                tLocalsess.set(session);<br />            }<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br /><span class="code-keyword">return</span> session;<br />    }<br /><br />    /*<br />     * closing the thread-safe session<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void closeSession(){<br /><br />        Session session = (Session) tLocalsess.get();<br />        tLocalsess.set(<span class="code-keyword">null</span>);<br /><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (session != <span class="code-keyword">null</span> &amp;&amp; session.isOpen()){<br />                session.close();<br />            }<br /><br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br />    /*<br />     * begin the transaction<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void beginTransaction(){<br />        Transaction tx = (Transaction) tLocaltx.get();<br /><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (tx == <span class="code-keyword">null</span>){<br />                tx = currentSession().beginTransaction();<br />                tLocaltx.set(tx);<br />            }<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br />    /*<br />     * close the transaction<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void commitTransaction(){<br />        Transaction tx = (Transaction) tLocaltx.get();<br /><span class="code-keyword">try</span>{<br /><span class="code-keyword">if</span> (tx != <span class="code-keyword">null</span> &amp;&amp; !tx.wasCommitted() &amp;&amp; !tx.wasRolledBack())<br />                tx.commit();<br />            tLocaltx.set(<span class="code-keyword">null</span>);<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br />    /*<br />     * <span class="code-keyword">for</span> rollbacking<br />     */<br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void rollbackTransaction(){<br />        Transaction tx = (Transaction) tLocaltx.get();<br /><span class="code-keyword">try</span>{<br />            tLocaltx.set(<span class="code-keyword">null</span>);<br /><span class="code-keyword">if</span> (tx != <span class="code-keyword">null</span> &amp;&amp; !tx.wasCommitted() &amp;&amp; !tx.wasRolledBack()){<br />                tx.rollback();<br />            }<br />        }<span class="code-keyword">catch</span> (HibernateException e){<br /><span class="code-keyword">throw</span><span class="code-keyword">new</span> InfrastructureException(e);<br />        }<br />    }<br /><br /><span class="code-keyword">private</span><span class="code-keyword">static</span> Session openSession() <span class="code-keyword">throws</span> HibernateException{<br /><span class="code-keyword">return</span> getSessionFactory().openSession();<br />    }<br /><br /><span class="code-keyword">private</span><span class="code-keyword">static</span> SessionFactory getSessionFactory() <span class="code-keyword">throws</span> HibernateException{<br /><span class="code-keyword">return</span> SingletonSessionFactory.getInstance();<br />    }<br />}</pre>
												</div>
										</div>
										<p>　filter中的程式碼如下</p>
										<div class="code" style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
												<div class="codeHeader" style="BORDER-BOTTOM-STYLE: solid">
														<b>HibernateSessionCloser.java</b>
												</div>
												<div class="codeContent">
														<pre class="code-java">
																<span class="code-keyword">public</span> class HibernateSessionCloser <span class="code-keyword">implements</span> Filter{<br /><br /><span class="code-keyword">protected</span> FilterConfig filterConfig = <span class="code-keyword">null</span>;<br /><br /><span class="code-keyword">public</span> void init(FilterConfig filterConfig)<span class="code-keyword">throws</span> ServletException{<br /><span class="code-keyword">this</span>.filterConfig = filterConfig;<br />    }<br /><br /><span class="code-keyword">public</span> void destroy(){<br /><span class="code-keyword">this</span>.filterConfig = <span class="code-keyword">null</span>;<br />    }    <br /><br /><span class="code-keyword">public</span> void doFilter(ServletRequest request, ServletResponse response,<br />                         FilterChain chain)<br /><span class="code-keyword">throws</span> IOException, ServletException {<br /><span class="code-keyword">try</span>{<br />            chain.doFilter(request, response);<br />        }<br /><span class="code-keyword">finally</span>{<br /><span class="code-keyword">try</span>{<br />                HibernateSessionUtil.commitTransaction();<br />            }<span class="code-keyword">catch</span> (InfrastructureException e){<br />                HibernateSessionUtil.rollbackTransaction();<br />            }<span class="code-keyword">finally</span>{<br />                HibernateSessionUtil.closeSession();<br />            }   <br />        }<br /><br />    }<br />}</pre>
												</div>
										</div>
										<p>然後在操作資料庫之前加上</p>
										<div class="code" style="BORDER-TOP-STYLE: solid; BORDER-RIGHT-STYLE: solid; BORDER-LEFT-STYLE: solid; BORDER-BOTTOM-STYLE: solid">
												<div class="codeContent">
														<pre class="code-java">HibernateSessionUtil.beginTransaction();<br />HibernateSessionUtil.currentSession();<span class="code-comment">//取得Session</span></pre>
												</div>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
<img src ="http://www.blogjava.net/lijiajia418/aggbug/65531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-24 15:24 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/24/65531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate Validator 简介</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65020.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 03:20:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65020.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65020.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65020.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65020.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#008000">在项目的业务属性中,你是不是要经常验证属性的取值范围呢. 想要了解比较优美的解决方案吗?           </font>
		</p>
		<p align="left">
				<font color="#008000">看看Hibernate Validator 是怎么做的吧.一见到她,相信你就会说: Oh God, 这就是我需要的.</font>
		</p>
		<p align="left">
				<span style="COLOR: red">任何获得Matrix授权的网站，转载请保留以下作者信息和链接：</span>
				<br />作者：icess(作者的blog:<a href="http://blog.matrix.org.cn/page/icess" target="_new">http://blog.matrix.org.cn/page/icess</a>)<br />关键字：Hibernate Validator</p>
		<p>用Annotations 给类或者类的属性加上约束(constraint),在运行期检查属性值是很优雅的.Hibernate Validator就是这样的一个框架.该框架是十分容易的(就像参考文档中宣称的那样),几乎没有什么学习曲线,Validator 是一个验证框架 不需要和Hibernate的其他部分绑定就可以使用,只要在你的项目中添加Hibernate-annotations.jar库就可以了.那么下面就让我们看看怎么使用吧.</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">Person.java 类</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">/*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* Created on 2006-1-12 Person.java</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* @author </font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">*/</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Length;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Min;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Valid;</font>
						<br />　</code>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">/<font color="#808000">/@Serializability  //测试自定义约束</font></span>
						</font>
				</code>
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">Person {</font>
						<br />
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private </b>
						</font>
						<font color="#000000">String name;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private int </b>
						</font>
						<font color="#000000">age;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private </b>
						</font>
						<font color="#000000">Address address;</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">Person() {}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#ff0000">@Valid //注意此处</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">Address getAddress() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">address;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setAddress(Address address) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.address = address;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Min(value = </font>
						<font color="#990000">1</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public int </b>
						</font>
						<font color="#000000">getAge() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">age;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setAge(</font>
						<font color="#7f0055">
								<b>int </b>
						</font>
						<font color="#000000">age) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.age = age;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Length(min = </font>
						<font color="#990000">4</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">String getName() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">name;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setName(String name) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.name = name;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<p align="left">　</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">Address.java 类</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">/*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* Created on 2006-1-12 Address.java</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* @author </font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">*/</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Length;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Max;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Min;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">Address {</font>
						<br />
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private </b>
						</font>
						<font color="#000000">String street;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>private int </b>
						</font>
						<font color="#000000">num;</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">Address() {}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Min(value = </font>
						<font color="#990000">1</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Max(value = </font>
						<font color="#990000">100</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public int </b>
						</font>
						<font color="#000000">getNum() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">num;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setNum(</font>
						<font color="#7f0055">
								<b>int </b>
						</font>
						<font color="#000000">num) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.num = num;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">@Length(min = </font>
						<font color="#990000">3</font>
						<font color="#000000">,max = </font>
						<font color="#990000">8</font>
						<font color="#000000">)</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public </b>
						</font>
						<font color="#000000">String getStreet() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>
						<font color="#000000">street;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">setStreet(String street) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>this</b>
						</font>
						<font color="#000000">.street = street;</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<div class="java" align="left">
				<p>上面是两个用 Validator Annotations 注释的 类. 每个属性都用 约束限制了.  下面看看测试的类吧:</p>
		</div>
		<p align="left">
				<!-- ======================================================== -->
				<!-- = Java Sourcecode to HTML automatically converted code = -->
				<!-- =   Java2Html Converter V4.1 2004 by Markus Gebhard  markus@jave.de   = -->
				<!-- =     Further information: http://www.java2html.de     = -->
				<font color="#000000">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">TestValidator.java 类</code>
				</font>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">/*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* Created on 2006-1-12</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">* @author icerain</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f7f5f">*/</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.ClassValidator;</font>
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.InvalidValue;</font>
						<br />
						<br />
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">TestValidator {</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public void </b>
						</font>
						<font color="#000000">test() {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">Address add = </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">Address();</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">add.setNum(</font>
						<font color="#990000">0</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">add.setStreet(</font>
						<font color="#2a00ff">"1"</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">Person p = </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">Person();</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">p.setAddress(add);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">p.setAge(</font>
						<font color="#990000">0</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">p.setName(</font>
						<font color="#2a00ff">"ice"</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#3f5fbf">/******************Test validator ********/</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#000000">    </font>
						<font color="#ff0000">// 注意该处只验证了Person 为了说明 @Valid 注释的使用</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">ClassValidator&lt;Person&gt; classValidator = </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">ClassValidator&lt;Person&gt; (Person.</font>
						<font color="#7f0055">
								<b>class</b>
						</font>
						<font color="#000000">);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">InvalidValue[] validMessages = classValidator.getInvalidValues(p);</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>for </b>
						</font>
						<font color="#000000">(InvalidValue value : validMessages) {</font>
						<br />
						<font color="#ffffff">      </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">System.out.println(</font>
						<font color="#2a00ff">"InvalidValue 的长度是:" </font>
						<font color="#000000">+ validMessages.length</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">" . 验证消息是: " </font>
						<font color="#000000">+ value.getMessage() </font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+ </font>
						<font color="#2a00ff">" . PropertyPath 是:" </font>
						<font color="#000000">+ value.getPropertyPath()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">" .\n\t PropertyName 是: " </font>
						<font color="#000000">+value.getPropertyName()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+ </font>
						<font color="#2a00ff">"Value 是: " </font>
						<font color="#000000">+ value.getValue()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">" Bean 是: "</font>
						<font color="#000000">+ value.getBean()</font>
						<br />
						<font color="#ffffff">        </font>
						<font color="#000000">+</font>
						<font color="#2a00ff">"\n\t BeanClass 是:" </font>
						<font color="#000000">+ value.getBeanClass());</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#ffffff">  </font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public static void </b>
						</font>
						<font color="#000000">main(String[] args) {</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>new </b>
						</font>
						<font color="#000000">TestValidator().test();</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<p align="left">　</p>
		<p align="left">程序的输出如下 <font size="2"></font></p>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 必须大于等于 1 . PropertyPath 是:age .</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@dd87b2</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 长度必须介于 4 与 2147483647 之间 . PropertyPath 是:name .</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@dd87b2</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 必须大于等于 1 . PropertyPath 是:address.num .</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">PropertyName 是: num. Value 是: 0 Bean 是: test.annotation.validator.Address@197d257</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Address</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">InvalidValue 的长度是:4 . 验证消息是: 长度必须介于 3 与 8 之间 . PropertyPath 是:address.street .</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">PropertyName 是: street. Value 是: 1 Bean 是: test.annotation.validator.Address@197d257</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Address</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">可以看出不满足约束的值都被指出了.</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">同时该句: <code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">ClassValidator&lt;Person&gt; classValidator = </font><font color="#7f0055"><b>new </b></font><font color="#000000">ClassValidator&lt;Person&gt; (Person.</font><font color="#7f0055"><b>class</b></font><font color="#000000">);</font></code></font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">我们只验证了 Person. 在Person里面的Address的属性 由于有<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#ff0000">@Valid Annotations </font>所以 Address的相关属性也被机联验证了 .</code></font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">
								<font size="2">如果 把</font>
						</span>
				</code>
				<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
						<font size="2">
								<font color="#ff0000">@Valid Annotations </font>去掉,结果如下:</font>
				</code>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">InvalidValue 的长度是:2 . 验证消息是: 必须大于等于 1 . PropertyPath 是:age .</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@18fef3d</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">InvalidValue 的长度是:2 . 验证消息是: 长度必须介于 4 与 2147483647 之间 . PropertyPath 是:name .</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@18fef3d</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">
						<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
				</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">可以看出 没有验证 Address.</span>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">当然了 ,你还可以只验证一个属性 , 没有必要验证整个类.只需要在调用</span>
						<font face="Courier New, Courier">classValidator.getInvalidValues(p,"age")方法时 加上你要验证的属性就可以了.如我们只想验证age 属性 把代码改为如下所示:</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" color="#ff0000">InvalidValue[] validMessages = classValidator.getInvalidValues(p,"age"); /</font>
						<font face="Courier New, Courier" color="#0000ff">/只验证age 属性</font>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">运行结果如下:</span>
				</code>
		</p>
		<p align="left">
				<font color="#ff00ff">InvalidValue 的长度是:1 . 验证消息是: 必须大于等于 1 . PropertyPath 是:age .</font>
		</p>
		<p align="left">
				<font color="#ff00ff">PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@1457cb</font>
		</p>
		<p align="left">
				<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">只是验证了 age 属性.</span>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">怎么样 ,很简单吧. 关于 <a title="Hibernate Annotation 中文文档" href="http://icess.my.china.com/hibernate/a/ref/index.htm" target="_blank">Hibernate</a> Validator 内建的验证Annotations 大家可以看看 API 或者 参考文档(中文版我正在翻译中 请访问我的 <a href="http://blog.matrix.org.cn/page/icess">Blog </a>获得最新信息).</span>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">如果你要写自己的约束呢 , 你不用担心 ,这也是很容易的. </span>
				</code>任何约束有两部分组成: [约束描述符 即注释]the constraint <span class="emphasis"><em>descriptor</em></span> (the annotation) 和[约束validator 即 实现类] the constraint <span class="emphasis"><em>validator</em></span> (the implementation class).<code><span style="FONT-FAMILY: 'Courier New',Courier">下面我们扩展Hibernate Test suit 中的一个Test 来讲解一下.</span></code></p>
		<font size="2">
				<p align="left">
						<code>
								<span style="FONT-FAMILY: 'Courier New',Courier">首先: 要声明一个</span>
						</code>constraint <span class="emphasis"><em>descriptor .如下:</em></span></p>
				<p align="left">
						<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
								<font color="#7f0055">
										<b>package </b>
								</font>
								<font color="#000000">test.annotation.validator;</font>
								<br />
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">java.lang.annotation.Documented;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.ElementType.TYPE;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.ElementType.FIELD;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.ElementType.METHOD;</font>
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">java.lang.annotation.Retention;</font>
								<br />
								<font color="#7f0055">
										<b>import static </b>
								</font>
								<font color="#000000">java.lang.annotation.RetentionPolicy.RUNTIME;</font>
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">java.lang.annotation.Target;</font>
								<br />
								<br />
								<font color="#7f0055">
										<b>import </b>
								</font>
								<font color="#000000">org.hibernate.validator.ValidatorClass;</font>
								<br />
								<br />
								<font color="#3f5fbf">/**</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">* Dummy sample of a bean-level validation annotation</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">*</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">* </font>
								<font color="#7f9fbf">@author </font>
								<font color="#3f5fbf">Emmanuel Bernard</font>
								<br />
								<font color="#ffffff"> </font>
								<font color="#3f5fbf">*/</font>
								<br />
								<font color="#000000">@ValidatorClass(SerializabilityValidator.</font>
								<font color="#7f0055">
										<b>class</b>
								</font>
								<font color="#000000">)</font>
								<br />
								<font color="#000000">@Target({METHOD,FIELD,TYPE})</font>
								<br />
								<font color="#000000">@Retention(RUNTIME)</font>
								<br />
								<font color="#000000">@Documented</font>
								<br />
								<font color="#7f0055">
										<b>public </b>
								</font>
								<font color="#000000">@interface Serializability {</font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#7f0055">
										<b>int </b>
								</font>
								<font color="#000000">num() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#990000">11</font>
								<font color="#000000">; </font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#000000">String message() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#2a00ff">"bean must be serialiable"</font>
								<font color="#000000">;</font>
								<br />
								<font color="#000000">}</font>
						</code>
				</p>
		</font>
		<p align="left">
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#000000">@ValidatorClass(SerializabilityValidator.</font>
								<font color="#7f0055">
										<b>class</b>
								</font>
								<font color="#000000">) 指出了 </font>
						</code>constraint <span class="emphasis"><em>validator 类.</em></span></font>
		</p>
		<p align="left">
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#000000">@Target({METHOD,FIELD,TYPE})</font>
								<br />
								<font color="#000000">@Retention(RUNTIME)</font>
								<br />
								<font color="#000000">@Documented                 </font>
						</code>
				</font>
		</p>
		<p align="left">
				<code style="FONT-FAMILY: 'Courier New',Courier">
						<font color="#000000">这几个我就不用解释了吧.</font>
				</code>
		</p>
		<p align="left">
				<code style="FONT-FAMILY: 'Courier New',Courier">
						<font color="#000000">Serializability 里面声明了一个 message 显示约束的提示信息. num 只是为了说明一个方面 在这里面没有实际用途用 .</font>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">然后就是 实现一个</span>
				</code>constraint <em><span class="emphasis">validator 类 该类要实现</span></em><tt class="literal">Validator&lt;ConstraintAnnotation&gt;</tt><em><span class="emphasis">.这里是</span></em><font size="2"><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">SerializabilityValidator.java 如下:</font></code></font></p>
		<p align="left">
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<font color="#3f7f5f">//$Id: SerializabilityValidator.java,v 1.3 2005/11/17 18:12:11 epbernard Exp $</font>
						<br />
						<font color="#7f0055">
								<b>package </b>
						</font>
						<font color="#000000">test.annotation.validator;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">java.io.Serializable;</font>
						<br />
						<br />
						<font color="#7f0055">
								<b>import </b>
						</font>
						<font color="#000000">org.hibernate.validator.Validator;</font>
						<br />
						<br />
						<font color="#3f5fbf">/**</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">* Sample of a bean-level validator</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">*</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">* </font>
						<font color="#7f9fbf">@author </font>
						<font color="#3f5fbf">Emmanuel Bernard</font>
						<br />
						<font color="#ffffff"> </font>
						<font color="#3f5fbf">*/</font>
						<br />
						<font color="#7f0055">
								<b>public class </b>
						</font>
						<font color="#000000">SerializabilityValidator </font>
						<font color="#7f0055">
								<b>implements </b>
						</font>
						<font color="#000000">Validator&lt;Serializability&gt;, Serializable {</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#7f0055">
								<b>public boolean </b>
						</font>
						<font color="#000000">isValid(Object value) {</font>
						<br />
						<font color="#ffffff">   </font>
						<font color="#00ff00">//这里只是Validator 里面的 实现验证规则的 方法. value 是要验证的值.</font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">System.out.println(</font>
						<font color="#2a00ff">"IN SerializabilityValidator isValid:"</font>
						<font color="#000000">+value.getClass()+</font>
						<font color="#2a00ff">": " </font>
						<font color="#000000">+value.toString()); </font>
						<br />
						<font color="#ffffff">    </font>
						<font color="#7f0055">
								<b>return </b>
						</font>value<font color="#3f7f5f"> </font><font color="#800080">instanceof</font><font color="#3f7f5f"> </font>Serializable<font color="#3f7f5f">;</font><br /><font color="#ffffff">  </font><font color="#000000">}</font><br /><br /><font color="#ffffff">  </font><font color="#7f0055"><b>public void </b></font><font color="#000000">initialize(Serializability parameters) {</font><br /><font color="#ffffff">    </font><font color="#3f7f5f">// 在这里可以 取得 </font></code>
				<font size="2">constraint <em><span class="emphasis">descriptor 里面的属性 如上面我们声明的 num </span></em></font>
				<code style="FONT-SIZE: 10pt; MARGIN: 0px; FONT-FAMILY: 'Courier New',Courier">
						<br />
						<font color="#ffffff">    </font>
						<font color="#000000">System.out.println(</font>
						<font color="#2a00ff">"IN SerializabilityValidator: parameters:"</font>
						<font color="#000000">+ parameters.num() );</font>
						<br />
						<font color="#ffffff">  </font>
						<font color="#000000">}</font>
						<br />
						<font color="#000000">}</font>
				</code>
		</p>
		<p align="left">然后在你的类中应用@<font size="2"><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">Serializability  就可以约束一个类实现</font></code></font><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">Serializable 接口了. 如下:</code></p>
		<p align="left">在我们的Person.java类 添加@<font size="2"><code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier"><font color="#000000">Serializability  Annotations ,把Person.java 中的 </font></code></font><code><font size="2"><span style="FONT-FAMILY: 'Courier New',Courier">/<font color="#808000">/@Serializability //测试自定义约束 </font>注释去掉就ok了.</span></font></code></p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">运行结果如下:</span>
						</font>
				</code>
				<font size="2">
						<p align="left">
								<font color="#ff00ff">InvalidValue 的长度是:3 . 验证消息是: </font>
								<font color="#008000">bean must be serialiable</font>
								<font color="#ff00ff">. PropertyPath 是:null .</font>
						</p>
						<p align="left">
								<font color="#ff00ff">PropertyName 是: null. Value 是: test.annotation.validator.Person@1a73d3c Bean 是: test.annotation.validator.Person@1a73d3c</font>
						</p>
						<p align="left">
								<font color="#ff00ff">BeanClass 是:class test.annotation.validator.Person</font>
						</p>
				</font>
		</p>
		<p>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">现在把Person类实现 java.io.Serializable 接口 则没有出现 验证错误消息.</span>
						</font>
				</code>
		</p>
		<p align="left">
				<code>
						<span style="FONT-FAMILY: 'Courier New',Courier">消息的国际化也是很简单的,把</span>
				</code>
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#000000">Serializability  中的message 改为以{}扩住的 属性文件的Key就可以了 </font>
						</code>
				</font>
		</p>
		<p align="left">
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#7f0055">
										<b>public </b>
								</font>
								<font color="#000000">@interface Serializability {</font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#7f0055">
										<b>int </b>
								</font>
								<font color="#000000">num() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#990000">11</font>
								<font color="#000000">; </font>
								<br />
								<font color="#ffffff">  </font>
								<font color="#000000">String message() </font>
								<font color="#7f0055">
										<b>default </b>
								</font>
								<font color="#2a00ff">"{Serializable}"; </font>
								<font color="#008000">//"bean must be serialiable"; </font>
								<font color="#ff0000">//消息的国际化</font>
								<br />
								<font color="#000000">}</font>
						</code>
				</font>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">然后编辑资料文件. 注意 该资源文件中要包括 <a title="Hibernate Annotation 中文文档" href="http://icess.my.china.com/hibernate/a/ref/index.htm" target="_blank">Hibernate</a> Validator 内建的资源. 可以在该org\hibernate\validator\resources 包里面的资源文件基础上修改 ,在打包里面 这样就可以了. 自己打包可能不太方便.你可以把该包里面的文件复制出来.然后放到你自己的项目包下在自己编辑, 该测试中 我是放在 test\resources 包下的.</span>
						</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">然后在 资源文件中添加 </span>
						</font>
				</code>
				<font size="2">
						<code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">
								<font color="#2a00ff">Serializable = '''''' </font>这么一行, 样例如下:</code>
				</font>
		</p>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">#<font color="#ff0000">DefaultValidatorMessages.properties (DefaultValidatorMessages_zh.properties 不再列出^_^)</font></span>
						</font>
				</code>
		</p>
		<p align="left">　</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" color="#ff0000" size="2">#下面是 <a title="Hibernate Annotation 中文文档" href="http://icess.my.china.com/hibernate/a/ref/index.htm" target="_blank">Hibernate</a> Validator 内建的国际化消息 </font>
				</code>
				<font size="2">
				</font>
		</p>
		<p align="left">
				<font size="2">validator.assertFalse=</font>
				<font color="#2a00ff" size="2">assertion</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">failed</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.assertTrue=</font>
				<font color="#2a00ff" size="2">assertion</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">failed</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.future=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">a</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">future</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">date</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.length=</font>
				<font color="#2a00ff" size="2">length</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">between</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{min}</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">and</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{max}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.max=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">less</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">than</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">or</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">equal</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">to</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{value}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.min=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">greater</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">than</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">or</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">equal</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">to</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{value}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.notNull=</font>
				<font color="#2a00ff" size="2">may</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">not</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">null</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.past=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">a</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">past</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">date</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.pattern=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">match</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">"{regex}"</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.range=</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">between</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{min}</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">and</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{max}</font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">validator.size=</font>
				<font color="#2a00ff" size="2">size</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">must</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">be</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">between</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{min}</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">and</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">{max}</font>
		</p>
		<p align="left">
				<font color="#2a00ff" size="2">#下面是自定义的消息</font>
		</p>
		<font size="2">
		</font>
		<p align="left">
				<font size="2">Serializable=</font>
				<font color="#2a00ff" size="2">Bean</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">not</font>
				<font size="2">
				</font>
				<font color="#2a00ff" size="2">Serializable  //加上自己定义的国际化消息. </font>
		</p>
		<font color="#2a00ff" size="2">
		</font>
		<p align="left">
				<code>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">在构造</span>
						</font>
						<font face="Courier New, Courier" size="2">ClassValidator</font>
						<font size="2">
								<span style="FONT-FAMILY: 'Courier New',Courier">时要添上 资源文件 如下:(在测试类中)</span>
						</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">ClassValidator&lt;Person&gt; classValidator = new ClassValidator&lt;Person&gt; (Person.class,<font color="#ff0000">ResourceBundle.getBundle("</font><font color="#0000ff">test.resources.DefaultValidatorMessages</font><font color="#ff0000">"</font>));//加载资源</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">这样就可以了 .  当然 你还可以 更改 <a title="Hibernate Annotation 中文文档" href="http://icess.my.china.com/hibernate/a/ref/index.htm" target="_blank">Hibernate</a> Validator 的消息(不是在上面的资源文件中直接修改</font>
				</code>
				<font size="2">validator.length = ... 等等 </font>
				<code>
						<font face="Courier New, Courier" size="2">) , 还记得 Validator 注释中有个 message 元素吗? 你以前用的都是默认值,现在你可以该为你自己定义的了.</font>
				</code>
				<font size="2">如:validator.length 我把他改为 "<font color="#0000ff">该字符串的长度不符合规定范围范围</font>". 在资源文件中添加一行键值属性对(key定义为 "<font color="#ff0000">myMsg</font>")如下:</font>
		</p>
		<p align="left">
				<font size="2">myMsg=<font color="#0000ff">该字符串的长度不符合规定范围范围</font></font>
		</p>
		<p align="left">
				<font size="2">并且还要在</font>
				<font color="#0000ff" size="2">@Length </font>
				<font size="2">注释中提供message的引用的key 如下</font>
				<font color="#0000ff" size="2">@Length(min = 4,message = "{</font>
				<font color="#ff0000" size="2">myMsg</font>
				<font color="#0000ff" size="2">}")</font>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">再一次运行测试 ,我们就可以看到上面两条自定义绑定的消息了 .如下:</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">InvalidValue 的长度是:3 . <font color="#008000">验证消息是</font>: <font color="#ff0000">Bean 不是 可 Serializable</font> . PropertyPath 是:null .<br />PropertyName 是: null. Value 是: test.annotation.validator.Person@1bd4722 Bean 是: test.annotation.validator.Person@1bd4722<br />BeanClass 是:class test.annotation.validator.Person</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier">
								<br />InvalidValue 的长度是:3 . <font color="#008000">验证消息是</font>: <font color="#ff0000">该字符串的长度不符合规定范围范围</font> . PropertyPath 是:name .<br />PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@1bd4722<br />BeanClass 是:class test.annotation.validator.Person</font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier">怎么样,比你想象的简单吧. </font>
				</code>
		</p>
		<p align="left">
				<code>
						<font face="Courier New, Courier" size="2">OK 上面我们讨论了 </font>
				</code>
				<a title="Hibernate Annotation 中文文档" href="http://icess.my.china.com/hibernate/a/ref/index.htm" target="_blank">Hibernate</a> Validator 的主要用法: 但是 该框架有什么用呢? ^_^</p>
		<p align="left">看到这里其实不用我在多说了 大家都知道怎么用,什么时候用. 作为一篇介绍性文章我还是在此给出一个最常用的例子吧,更好的使用方式大家慢慢挖掘吧.</p>
		<p align="left">比如 : 你现在在开发一个人力资源(HR)系统 (其实是我们ERP课程的一个作业 ^_^), 里面要处理大量的数据,尤其是在输入各种资料时 如 登记员工信息. 如果你公司的员工的年龄要求是18 -- 60 那么你所输入的年龄就不能超出这个范围. 你可能会说这很容易啊 , 不用Validator就可以解决啊.这保持数据前验证就可以啦 如if ( e.getAge() &gt; 60 || e.getAge() &lt; 18 ) ........ 给出错误信息 然后提示重新输入不就OK啦 用得着 兴师动众的来个第三方框架吗? </p>
		<p align="left">是啊 当就验证这一个属性时, 没有必要啊 ! 但是一个真正的HR 系统,会只有一个属性要验证吗? 恐怕要有N多吧</p>
		<p align="left">你要是每一个都那样 写一段验证代码 是不是很烦啊 ,况且也不方便代码重用. 现在考虑一些 Validator 是不是更高效啊,拦截到 约束违例的 属性 就可以直接得到 国际化的消息 可以把该消息显示到一个弹出对话框上 提示更正  !</p>
		<p align="left">Validator的用处不只这一种 ,你可以想到如何用呢 ! 欢迎发表你的高见!!</p>
		<p align="left">OK 到此 我们的 <a title="Hibernate Annotation 中文文档" href="http://icess.my.china.com/hibernate/a/ref/index.htm" target="_blank">Hibernate</a> Validator 之旅就要先告一段落了 . 希望这是令你心旷神怡的一次寒冬之旅,</p>
		<p align="left">把你学到的应用到你的项目中吧,一定会提高你的生产率的. 相信我 ,没错的  ^_^ !</p>
<img src ="http://www.blogjava.net/lijiajia418/aggbug/65020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 11:20 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 Hibernate 和 Spring AOP 构建泛型类型安全的 DAO</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65015.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 03:03:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65015.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65015.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65015.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65015.html</trackback:ping><description><![CDATA[由于 Java™ 5 泛型的采用，有关泛型类型安全 Data Access Object (DAO) 实现的想法变得切实可行。在本文中，系统架构师 Per Mellqvist 展示了基于 Hibernate 的泛型 DAO 实现类。然后展示如何使用 Spring AOP introductions 将类型安全接口添加到类中以便于查询执行。 
<blockquote></blockquote><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES--><p>对于大多数开发人员，为系统中的每个 DAO 编写几乎相同的代码到目前为止已经成为一种习惯。虽然所有人都将这种重复标识为 “代码味道”，但我们大多数都已经学会忍受它。其实有解决方案。可以使用许多 ORM 工具来避免代码重复。例如，使用 Hibernate，您可以简单地为所有的持久域对象直接使用会话操作。这种方法的缺点是损失了类型安全。</p><p>为什么您要为数据访问代码提供类型安全接口？我会争辩说，当它与现代 IDE 工具一起使用时，会减少编程错误并提高生产率。首先，类型安全接口清楚地指明哪些域对象具有可用的持久存储。其次，它消除了易出错的类型强制转换的需要（这是一个在查询操作中比在 CRUD 中更常见的问题）。最后，它有效利用了今天大多数 IDE 具备的自动完成特性。使用自动完成是记住什么查询可用于特定域类的快捷方法。</p><p>在本文中，我将为您展示如何避免再三地重复 DAO 代码，而仍保留类型安全接口的优点。事实上，您需要为每个新 DAO 编写的只是 Hibernate 映射文件、无格式旧 Java 接口以及 Spring 配置文件中的 10 行。</p><p><a name="N10057"><span class="atitle"><font face="Arial" size="4">DAO 实现</font></span></a></p><p>DAO 模式对任何企业 Java 开发人员来说都应该很熟悉。但是模式的实现各不相同，所以我们来澄清一下本文提供的 DAO 实现背后的假设：</p><ul><li>系统中的所有数据库访问都通过 DAO 进行以实现封装。 
</li><li>每个 DAO 实例负责一个主要域对象或实体。如果域对象具有独立生命周期，它应具有自己的 DAO。 
</li><li>DAO 负责域对象的创建、读取（按主键）、更新和删除（creations, reads, updates, and deletions，CRUD）。 
</li><li>DAO 可允许基于除主键之外的标准进行查询。我将之称为<i>查找器方法</i> 或<i>查找器</i>。查找器的返回值通常是 DAO 负责的域对象集合。 
</li><li>DAO 不负责处理事务、会话或连接。这些不由 DAO 处理是为了实现灵活性。 </li></ul><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><p><a name="N10078"><span class="atitle"><font face="Arial" size="4">泛型 DAO 接口</font></span></a></p><p>泛型 DAO 的基础是其 CRUD 操作。下面的接口定义泛型 DAO 的方法：</p><br /><a name="listing1"><b>清单 1. 泛型 DAO 接口</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public interface GenericDao &lt;T, PK extends Serializable&gt; {

    /** Persist the newInstance object into database */
    PK create(T newInstance);

    /** Retrieve an object that was previously persisted to the database using
     *   the indicated id as primary key
     */
    T read(PK id);

    /** Save changes made to a persistent object.  */
    void update(T transientObject);

    /** Remove an object from persistent storage in the database */
    void delete(T persistentObject);
}

</pre></code></td></tr></tbody></table><br /><p><a name="N1008B"><span class="smalltitle"><strong><font face="Arial" size="3">实现接口</font></strong></span></a></p><p>用 Hibernate 实现清单 1 中的接口十分简单，如清单 2 所示。它只需调用底层 Hibernate 方法和添加强制类型转换。Spring 负责会话和事务管理。（当然，我假设这些函数已做了适当的设置，但该主题在 Hibernate 和 Springt 手册中有详细介绍。）</p><br /><a name="listing2"><b>清单 2. 第一个泛型 DAO 实现</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public class GenericDaoHibernateImpl &lt;T, PK extends Serializable&gt;
    implements GenericDao&lt;T, PK&gt;, FinderExecutor {
    private Class&lt;T&gt; type;

    public GenericDaoHibernateImpl(Class&lt;T&gt; type) {
        this.type = type;
    }

    public PK create(T o) {
        return (PK) getSession().save(o);
    }

    public T read(PK id) {
        return (T) getSession().get(type, id);
    }

    public void update(T o) {
        getSession().update(o);
    }

    public void delete(T o) {
        getSession().delete(o);
    }

    // Not showing implementations of getSession() and setSessionFactory()
            }
</pre></code></td></tr></tbody></table><br /><p><a name="N1009E"><span class="smalltitle"><strong><font face="Arial" size="3">Spring 配置</font></strong></span></a></p><p>最后，在 Spring 配置中，我创建了 <code>GenericDaoHibernateImpl</code> 的一个实例。必须告诉 <code>GenericDaoHibernateImpl</code> 的构造函数 DAO 实例将负责哪个域类。只有这样，Hibernate 才能在运行时知道由 DAO 管理的对象类型。在清单 3 中，我将域类 <code>Person</code> 从示例应用程序传递给构造函数，并将先前配置的 Hibernate 会话工厂设置为已实例化的 DAO 的参数：</p><br /><a name="listing3"><b>清单 3. 配置 DAO</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">&lt;bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl"&gt;
        &lt;constructor-arg&gt;
            &lt;value&gt;genericdaotest.domain.Person&lt;/value&gt;
        &lt;/constructor-arg&gt;
        &lt;property name="sessionFactory"&gt;
            &lt;ref bean="sessionFactory"/&gt;
        &lt;/property&gt;
&lt;/bean&gt;
        </pre></code></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N100BD"><span class="atitle"><font face="Arial" size="4">可用的泛型 DAO</font></span></a></p><p>我还没有完成，但我所完成的确实已经可以使用了。在清单 4 中，可以看到原封不动使用该泛型 DAO 的示例：</p><br /><a name="listing4"><b>清单 4. 使用 DAO</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public void someMethodCreatingAPerson() {
    ...
    GenericDao dao = (GenericDao)
     beanFactory.getBean("personDao"); // This should normally be injected

    Person p = new Person("Per", 90);
    dao.create(p);
}
        </pre></code></td></tr></tbody></table><br /><p>现在，我有一个能够进行类型安全 CRUD 操作的泛型 DAO。让子类 <code>GenericDaoHibernateImpl</code> 为每个域对象添加查询能力将非常合理。因为本文的目的在于展示如何不为每个查询编写显式的 Java 代码来实现查询，但是，我将使用其他两个工具将查询引入 DAO，也就是 Spring AOP 和 Hibernate 命名的查询。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N100D7"><span class="atitle"><font face="Arial" size="4">Spring AOP introductions</font></span></a></p><p>可以使用 Spring AOP 中的 introductions 将功能添加到现有对象，方法是将功能包装在代理中，定义应实现的接口，并将所有先前未支持的方法指派到单个处理程序。在我的 DAO 实现中，我使用 introductions 将许多查找器方法添加到现有泛型 DAO 类中。因为查找器方法是特定于每个域对象的，因此将其应用于泛型 DAO 的类型化接口。</p><p>Spring 配置如清单 5 所示：</p><br /><a name="listing5"><b>清单 5. FinderIntroductionAdvisor 的 Spring 配置</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">&lt;bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/&gt;

&lt;bean id="abstractDaoTarget"
        class="genericdao.impl.GenericDaoHibernateImpl" abstract="true"&gt;
        &lt;property name="sessionFactory"&gt;
            &lt;ref bean="sessionFactory"/&gt;
        &lt;/property&gt;
&lt;/bean&gt;

&lt;bean id="abstractDao"
        class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true"&gt;
        &lt;property name="interceptorNames"&gt;
            &lt;list&gt;
                &lt;value&gt;finderIntroductionAdvisor&lt;/value&gt;
            &lt;/list&gt;
        &lt;/property&gt;
&lt;/bean&gt;
        </pre></code></td></tr></tbody></table><br /><p>在清单 5 的配置文件中，我定义了三个 Spring bean。第一个 bean 是 FinderIntroductionAdvisor，它处理引入到 DAO 的所有方法，这些方法在 <code>GenericDaoHibernateImpl</code> 类中不可用。我稍后将详细介绍 Advisor bean。</p><p>第二个 bean 是 “抽象的”。在 Spring 中，这意味着该 bean 可在其他 bean 定义中被重用，但不被实例化。除了抽象特性之外，该 bean 定义只指出我想要 <code>GenericDaoHibernateImpl</code> 的实例以及该实例需要对 <code>SessionFactory</code> 的引用。注意，<code>GenericDaoHibernateImpl</code> 类仅定义一个构造函数，该构造函数接受域类作为其参数。因为该 bean 定义是抽象的，所以我将来可以无数次地重用该定义，并将构造函数参数设置为合适的域类。</p><p>最后，第三个也是最有趣的 bean 将 <code>GenericDaoHibernateImpl</code> 的 vanilla 实例包装在代理中，赋予其执行查找器方法的能力。该 bean 定义也是抽象的，不指定希望引入到 vanilla DAO 的接口。该接口对于每个具体的实例是不同的。注意，清单 5 显示的整个配置仅定义一次。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" style="ZOOM: 160%" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N1010A"><span class="atitle"><font face="Arial" size="4">扩展 GenericDAO</font></span></a></p><p>当然，每个 DAO 的接口都基于 <code>GenericDao</code> 接口。我只需使该接口适应特定的域类并扩展该接口以包括查找器方法。在清单 6 中，可以看到为特定目的扩展的 <code>GenericDao</code> 接口示例：</p><br /><a name="listing6"><b>清单 6. PersonDao 接口</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public interface PersonDao extends GenericDao&lt;Person, Long&gt; {
    List&lt;Person&gt; findByName(String name);
}

</pre></code></td></tr></tbody></table><br /><p>很明显，清单 6 中定义的方法旨在按名称查找 <code>Person</code>。必需的 Java 实现代码全部是泛型代码，在添加更多 DAO 时不需要任何更新。</p><p><a name="N1012C"><span class="smalltitle"><strong><font face="Arial" size="3">配置 PersonDao</font></strong></span></a></p><p>因为 Spring 配置依赖于先前定义的 “抽象” bean，因此它变得相当简洁。我需要指出 DAO 负责哪个域类，并且需要告诉 Springs 该 DAO 应实现哪个接口（一些方法是直接使用，一些方法则是通过使用 introductions 来使用）。清单 7 展示了 <code>PersonDAO</code> 的 Spring 配置文件：</p><br /><a name="listing7"><b>清单 7. PersonDao 的 Spring 配置</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">&lt;bean id="personDao" parent="abstractDao"&gt;
    &lt;property name="proxyInterfaces"&gt;
        &lt;value&gt;genericdaotest.dao.PersonDao&lt;/value&gt;
    &lt;/property&gt;
    &lt;property name="target"&gt;
        &lt;bean parent="abstractDaoTarget"&gt;
            &lt;constructor-arg&gt;
                &lt;value&gt;genericdaotest.domain.Person&lt;/value&gt;
            &lt;/constructor-arg&gt;
        &lt;/bean&gt;
    &lt;/property&gt;
&lt;/bean&gt;
        </pre></code></td></tr></tbody></table><br /><p>在清单 8 中，可以看到使用了这个更新后的 DAO 版本：</p><br /><a name="listing8"><b>清单 8. 使用类型安全接口</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public void someMethodCreatingAPerson() {
    ...
    PersonDao dao = (PersonDao)
     beanFactory.getBean("personDao"); // This should normally be injected

    Person p = new Person("Per", 90);
    dao.create(p);

    List&lt;Person&gt; result = dao.findByName("Per"); // Runtime exception
}
        </pre></code></td></tr></tbody></table><br /><p>虽然清单 8 中的代码是使用类型安全 <code>PersonDao</code> 接口的正确方法，但 DAO 的实现并不完整。调用 <code>findByName()</code> 会导致运行时异常。问题在于我还没有实现调用 <code>findByName()</code> 所必需的查询。剩下要做的就是指定查询。为更正该问题，我使用了 Hibernate 命名查询。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N1015F"><span class="atitle"><font face="Arial" size="4">Hibernate 命名查询</font></span></a></p><p>使用 Hibernate，可以在 Hibernate 映射文件 (hbm.xml) 中定义 HQL 查询并为其命名。稍后可以通过简单地引用给定名称来在 Java 代码中使用该查询。该方法的优点之一是能够在部署时优化查询，而无需更改代码。您一会将会看到，另一个优点是无需编写任何新 Java 实现代码，就可以实现 “完整的” DAO。清单 9 是带有命名查询的映射文件的示例：</p><br /><a name="listing9"><b>清单 9. 带有命名查询的映射文件</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section"> &lt;hibernate-mapping package="genericdaotest.domain"&gt;
     &lt;class name="Person"&gt;
         &lt;id name="id"&gt;
             &lt;generator class="native"/&gt;
         &lt;/id&gt;
         &lt;property name="name" /&gt;
         &lt;property name="weight" /&gt;
     &lt;/class&gt;

     &lt;query name="Person.findByName"&gt;
         &lt;![CDATA[select p from Person p where p.name = ? ]]&gt;
     &lt;/query&gt;
 &lt;/hibernate-mapping&gt;
        </pre></code></td></tr></tbody></table><br /><p>清单 9 定义了域类 <code>Person</code> 的 Hibernate 映射，该域类具有两个属性：<code>name</code> 和 <code>weight</code>。<code>Person</code> 是具有上述属性的简单 POJO。该文件还包含一个在数据库中查找 <code>Person</code> 所有实例的查询，其中 “name” 等于提供的参数。Hibernate 不为命名查询提供任何真正的名称空间功能。出于讨论目的，我为所有查询名称都加了域类的短（非限定）名称作为前缀。在现实世界中，使用包括包名称的完全类名可能是更好的主意。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10189"><span class="atitle"><font face="Arial" size="4">逐步概述</font></span></a></p><p>您已经看到了为任何域对象创建和配置新 DAO 所必需的全部步骤。三个简单的步骤是：</p><ol><li>定义一个接口，它扩展 <code>GenericDao</code> 并包含所需的任何查找器方法。 
</li><li>将每个查找器的命名查询添加到域对象的 hbm.xml 映射文件。 
</li><li>为 DAO 添加 10 行 Spring 配置文件。 </li></ol><p>查看执行查找器方法的代码（只编写了一次！）来结束我的讨论。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" style="ZOOM: 70%" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N101A5"><span class="atitle"><font face="Arial" size="4">可重用的 DAO 类</font></span></a></p><p>使用的 Spring advisor 和 interceptor 很简单，事实上它们的工作是向后引用 <code>GenericDaoHibernateImplClass</code>。方法名以 “find” 打头的所有调用都传递给 DAO 和单个方法 <code>executeFinder()</code>。</p><br /><a name="listing10"><b>清单 10. FinderIntroductionAdvisor 的实现</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {
    public FinderIntroductionAdvisor() {
        super(new FinderIntroductionInterceptor());
    }
}

public class FinderIntroductionInterceptor implements IntroductionInterceptor {

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();

        String methodName = methodInvocation.getMethod().getName();
        if (methodName.startsWith("find")) {
            Object[] arguments = methodInvocation.getArguments();
            return genericDao.executeFinder(methodInvocation.getMethod(), arguments);
        } else {
            return methodInvocation.proceed();
        }
    }

    public boolean implementsInterface(Class intf) {
        return intf.isInterface() &amp;&amp; FinderExecutor.class.isAssignableFrom(intf);
    }
}
</pre></code></td></tr></tbody></table><br /><p><a name="N101C0"><span class="smalltitle"><strong><font face="Arial" size="3">executeFinder() 方法</font></strong></span></a></p><p>清单 10 的实现中惟一缺少的是 <code>executeFinder()</code> 实现。该代码查看调用的类和方法的名称，并使用配置上的约定将其与 Hibernate 查询的名称相匹配。还可以使用 <code>FinderNamingStrategy</code> 来支持其他命名查询的方法。默认实现查找叫做 “<code>ClassName.methodName</code>” 的查询，其中 <code>ClassName</code> 是不带包的短名称。清单 11 完成了泛型类型安全 DAO 实现： </p><br /><a name="listing11"><b>清单 11. executeFinder() 的实现</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><code><pre class="section">public List&lt;T&gt; executeFinder(Method method, final Object[] queryArgs) {
     final String queryName = queryNameFromMethod(method);
     final Query namedQuery = getSession().getNamedQuery(queryName);
     String[] namedParameters = namedQuery.getNamedParameters();
     for(int i = 0; i &lt; queryArgs.length; i++) {
             Object arg = queryArgs[i];
             Type argType =  namedQuery.setParameter(i, arg);
      }
      return (List&lt;T&gt;) namedQuery.list();
 }

 public String queryNameFromMethod(Method finderMethod) {
     return type.getSimpleName() + "." + finderMethod.getName();
 }
</pre></code></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><a href="http://www.ibm.com/i/v14/rules/blue_rule.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="500" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><a href="http://www.ibm.com/i/c.gif" target="_blank"><img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" /></a><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#main"><b><font color="#996699"></font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N101E3"><span class="atitle"><font face="Arial" size="4">结束语</font></span></a></p><p>在 Java 5 之前，该语言不支持编写既类型安全<i>又</i> 泛型的代码，您必须只能选择其中之一。在本文中，您已经看到一个结合使用 Java 5 泛型与 Spring 和 Hibernate（以及 AOP）等工具来提高生产率的示例。泛型类型安全 DAO 类相当容易编写 —— 您只需要单个接口、一些命名查询和为 Spring 配置添加的 10 行代码 —— 而且可以极大地减少错误并节省时间。</p><p>几乎本文的所有代码都是可重用的。尽管您的 DAO 类可能包含此处没有实现的查询和操作类型（比如，批操作），但使用我所展示的技术，您至少应该能够实现其中的一部分。参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html?ca=dwcn-newsletter-java#resources"><font color="#996699">参考资料</font></a> 了解其他泛型类型安全 DAO 类实现。</p><p><a name="N101F6"><span class="smalltitle"><strong><font face="Arial" size="3">致谢</font></strong></span></a></p><p>自 Java 语言中出现泛型以来，单个泛型类型安全 DAO 的概念已经成为主题。我曾在 JavaOne 2004 中与 Don Smith 简要讨论了泛型 DAO 的灵活性。本文使用的 DAO 实现类旨在作为示例实现，实际上还存在其他实现。例如，Christian Bauer 已经发布了带有 CRUD 操作和标准搜索的实现，Eric Burke 也在该领域做出了工作。我确信将会有更多的实现出现。我要额外感谢 Christian，他目睹了我编写泛型类型安全 DAO 的第一次尝试并提出改进建议。最后，我要感谢 Ramnivas Laddad 的无价帮助，他审阅了本文。</p><img src ="http://www.blogjava.net/lijiajia418/aggbug/65015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 11:03 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate调用mysql5.0存储过程小记</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65007.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 02:55:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65007.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65007.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65007.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65007.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65007.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 准备工作:1.hibernate3到这下载hibernate3:		http://sourceforge.net/project/showfiles.phpgroup_id=40712&amp;package_id=127784&amp;release_id=403223		2.mysql (注意一定要用mysql5.0和最新驱动) mysql官方网站http://www.mysql.co...&nbsp;&nbsp;<a href='http://www.blogjava.net/lijiajia418/archive/2006/08/22/65007.html'>阅读全文</a><img src ="http://www.blogjava.net/lijiajia418/aggbug/65007.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 10:55 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65007.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>不要重复DAO！使用Hibernate 和Spring AOP 构建泛型类型安全的DAO</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65005.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65005.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65005.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65005.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65005.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65005.html</trackback:ping><description><![CDATA[
		<blockquote>由于 Java™ 5 泛型的采用，有关泛型类型安全 Data Access Object (DAO) 实现的想法变得切实可行。在本文中，系统架构师 Per Mellqvist 展示了基于 Hibernate 的泛型 DAO 实现类。然后展示如何使用 Spring AOP introductions 将类型安全接口添加到类中以便于查询执行。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>对于大多数开发人员，为系统中的每个 DAO 编写几乎相同的代码到目前为止已经成为一种习惯。虽然所有人都将这种重复标识为 “代码味道”，但我们大多数都已经学会忍受它。其实有解决方案。可以使用许多 ORM 工具来避免代码重复。例如，使用 Hibernate，您可以简单地为所有的持久域对象直接使用会话操作。这种方法的缺点是损失了类型安全。</p>
		<p>为什么您要为数据访问代码提供类型安全接口？我会争辩说，当它与现代 IDE 工具一起使用时，会减少编程错误并提高生产率。首先，类型安全接口清楚地指明哪些域对象具有可用的持久存储。其次，它消除了易出错的类型强制转换的需要（这是一个在查询操作中比在 CRUD 中更常见的问题）。最后，它有效利用了今天大多数 IDE 具备的自动完成特性。使用自动完成是记住什么查询可用于特定域类的快捷方法。</p>
		<p>在本文中，我将为您展示如何避免再三地重复 DAO 代码，而仍保留类型安全接口的优点。事实上，您需要为每个新 DAO 编写的只是 Hibernate 映射文件、无格式旧 Java 接口以及 Spring 配置文件中的 10 行。</p>
		<p>
				<a name="N10057">
						<span class="atitle">
								<font face="Arial" size="4">DAO 实现</font>
						</span>
				</a>
		</p>
		<p>DAO 模式对任何企业 Java 开发人员来说都应该很熟悉。但是模式的实现各不相同，所以我们来澄清一下本文提供的 DAO 实现背后的假设：</p>
		<ul>
				<li>系统中的所有数据库访问都通过 DAO 进行以实现封装。 
</li>
				<li>每个 DAO 实例负责一个主要域对象或实体。如果域对象具有独立生命周期，它应具有自己的 DAO。 
</li>
				<li>DAO 负责域对象的创建、读取（按主键）、更新和删除（creations, reads, updates, and deletions，CRUD）。 
</li>
				<li>DAO 可允许基于除主键之外的标准进行查询。我将之称为<i>查找器方法</i> 或<i>查找器</i>。查找器的返回值通常是 DAO 负责的域对象集合。 
</li>
				<li>DAO 不负责处理事务、会话或连接。这些不由 DAO 处理是为了实现灵活性。 </li>
		</ul>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10078">
						<span class="atitle">
								<font face="Arial" size="4">泛型 DAO 接口</font>
						</span>
				</a>
		</p>
		<p>泛型 DAO 的基础是其 CRUD 操作。下面的接口定义泛型 DAO 的方法：</p>
		<br />
		<a name="listing1">
				<b>清单 1. 泛型 DAO 接口</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public interface GenericDao &lt;T, PK extends Serializable&gt; {<br /><br />    /** Persist the newInstance object into database */<br />    PK create(T newInstance);<br /><br />    /** Retrieve an object that was previously persisted to the database using<br />     *   the indicated id as primary key<br />     */<br />    T read(PK id);<br /><br />    /** Save changes made to a persistent object.  */<br />    void update(T transientObject);<br /><br />    /** Remove an object from persistent storage in the database */<br />    void delete(T persistentObject);<br />}<br /><br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1008B">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">实现接口</font>
								</strong>
						</span>
				</a>
		</p>
		<p>用 Hibernate 实现清单 1 中的接口十分简单，如清单 2 所示。它只需调用底层 Hibernate 方法和添加强制类型转换。Spring 负责会话和事务管理。（当然，我假设这些函数已做了适当的设置，但该主题在 Hibernate 和 Springt 手册中有详细介绍。）</p>
		<br />
		<a name="listing2">
				<b>清单 2. 第一个泛型 DAO 实现</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public class GenericDaoHibernateImpl &lt;T, PK extends Serializable&gt;<br />    implements GenericDao&lt;T, PK&gt;, FinderExecutor {<br />    private Class&lt;T&gt; type;<br /><br />    public GenericDaoHibernateImpl(Class&lt;T&gt; type) {<br />        this.type = type;<br />    }<br /><br />    public PK create(T o) {<br />        return (PK) getSession().save(o);<br />    }<br /><br />    public T read(PK id) {<br />        return (T) getSession().get(type, id);<br />    }<br /><br />    public void update(T o) {<br />        getSession().update(o);<br />    }<br /><br />    public void delete(T o) {<br />        getSession().delete(o);<br />    }<br /><br />    // Not showing implementations of getSession() and setSessionFactory()<br />            }<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1009E">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">Spring 配置</font>
								</strong>
						</span>
				</a>
		</p>
		<p>最后，在 Spring 配置中，我创建了 <code><font face="新宋体">GenericDaoHibernateImpl</font></code> 的一个实例。必须告诉 <code><font face="新宋体">GenericDaoHibernateImpl</font></code> 的构造函数 DAO 实例将负责哪个域类。只有这样，Hibernate 才能在运行时知道由 DAO 管理的对象类型。在清单 3 中，我将域类 <code><font face="新宋体">Person</font></code> 从示例应用程序传递给构造函数，并将先前配置的 Hibernate 会话工厂设置为已实例化的 DAO 的参数：</p>
		<br />
		<a name="listing3">
				<b>清单 3. 配置 DAO</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">&lt;bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl"&gt;<br />        &lt;constructor-arg&gt;<br />            &lt;value&gt;genericdaotest.domain.Person&lt;/value&gt;<br />        &lt;/constructor-arg&gt;<br />        &lt;property name="sessionFactory"&gt;<br />            &lt;ref bean="sessionFactory"/&gt;<br />        &lt;/property&gt;<br />&lt;/bean&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100BD">
						<span class="atitle">
								<font face="Arial" size="4">可用的泛型 DAO</font>
						</span>
				</a>
		</p>
		<p>我还没有完成，但我所完成的确实已经可以使用了。在清单 4 中，可以看到原封不动使用该泛型 DAO 的示例：</p>
		<br />
		<a name="listing4">
				<b>清单 4. 使用 DAO</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public void someMethodCreatingAPerson() {<br />    ...<br />    GenericDao dao = (GenericDao)<br />     beanFactory.getBean("personDao"); // This should normally be injected<br /><br />    Person p = new Person("Per", 90);<br />    dao.create(p);<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在，我有一个能够进行类型安全 CRUD 操作的泛型 DAO。让子类 <code><font face="新宋体">GenericDaoHibernateImpl</font></code> 为每个域对象添加查询能力将非常合理。因为本文的目的在于展示如何不为每个查询编写显式的 Java 代码来实现查询，但是，我将使用其他两个工具将查询引入 DAO，也就是 Spring AOP 和 Hibernate 命名的查询。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100D7">
						<span class="atitle">
								<font face="Arial" size="4">Spring AOP introductions</font>
						</span>
				</a>
		</p>
		<p>可以使用 Spring AOP 中的 introductions 将功能添加到现有对象，方法是将功能包装在代理中，定义应实现的接口，并将所有先前未支持的方法指派到单个处理程序。在我的 DAO 实现中，我使用 introductions 将许多查找器方法添加到现有泛型 DAO 类中。因为查找器方法是特定于每个域对象的，因此将其应用于泛型 DAO 的类型化接口。</p>
		<p>Spring 配置如清单 5 所示：</p>
		<br />
		<a name="listing5">
				<b>清单 5. FinderIntroductionAdvisor 的 Spring 配置</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">&lt;bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/&gt;<br /><br />&lt;bean id="abstractDaoTarget"<br />        class="genericdao.impl.GenericDaoHibernateImpl" abstract="true"&gt;<br />        &lt;property name="sessionFactory"&gt;<br />            &lt;ref bean="sessionFactory"/&gt;<br />        &lt;/property&gt;<br />&lt;/bean&gt;<br /><br />&lt;bean id="abstractDao"<br />        class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true"&gt;<br />        &lt;property name="interceptorNames"&gt;<br />            &lt;list&gt;<br />                &lt;value&gt;finderIntroductionAdvisor&lt;/value&gt;<br />            &lt;/list&gt;<br />        &lt;/property&gt;<br />&lt;/bean&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 5 的配置文件中，我定义了三个 Spring bean。第一个 bean 是 FinderIntroductionAdvisor，它处理引入到 DAO 的所有方法，这些方法在 <code><font face="新宋体">GenericDaoHibernateImpl</font></code> 类中不可用。我稍后将详细介绍 Advisor bean。</p>
		<p>第二个 bean 是 “抽象的”。在 Spring 中，这意味着该 bean 可在其他 bean 定义中被重用，但不被实例化。除了抽象特性之外，该 bean 定义只指出我想要 <code><font face="新宋体">GenericDaoHibernateImpl</font></code> 的实例以及该实例需要对 <code><font face="新宋体">SessionFactory</font></code> 的引用。注意，<code><font face="新宋体">GenericDaoHibernateImpl</font></code> 类仅定义一个构造函数，该构造函数接受域类作为其参数。因为该 bean 定义是抽象的，所以我将来可以无数次地重用该定义，并将构造函数参数设置为合适的域类。</p>
		<p>最后，第三个也是最有趣的 bean 将 <code><font face="新宋体">GenericDaoHibernateImpl</font></code> 的 vanilla 实例包装在代理中，赋予其执行查找器方法的能力。该 bean 定义也是抽象的，不指定希望引入到 vanilla DAO 的接口。该接口对于每个具体的实例是不同的。注意，清单 5 显示的整个配置仅定义一次。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1010A">
						<span class="atitle">
								<font face="Arial" size="4">扩展 GenericDAO</font>
						</span>
				</a>
		</p>
		<p>当然，每个 DAO 的接口都基于 <code><font face="新宋体">GenericDao</font></code> 接口。我只需使该接口适应特定的域类并扩展该接口以包括查找器方法。在清单 6 中，可以看到为特定目的扩展的 <code><font face="新宋体">GenericDao</font></code> 接口示例：</p>
		<br />
		<a name="listing6">
				<b>清单 6. PersonDao 接口</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public interface PersonDao extends GenericDao&lt;Person, Long&gt; {<br />    List&lt;Person&gt; findByName(String name);<br />}<br /><br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>很明显，清单 6 中定义的方法旨在按名称查找 <code><font face="新宋体">Person</font></code>。必需的 Java 实现代码全部是泛型代码，在添加更多 DAO 时不需要任何更新。</p>
		<p>
				<a name="N1012C">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">配置 PersonDao</font>
								</strong>
						</span>
				</a>
		</p>
		<p>因为 Spring 配置依赖于先前定义的 “抽象” bean，因此它变得相当简洁。我需要指出 DAO 负责哪个域类，并且需要告诉 Springs 该 DAO 应实现哪个接口（一些方法是直接使用，一些方法则是通过使用 introductions 来使用）。清单 7 展示了 <code><font face="新宋体">PersonDAO</font></code> 的 Spring 配置文件：</p>
		<br />
		<a name="listing7">
				<b>清单 7. PersonDao 的 Spring 配置</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">&lt;bean id="personDao" parent="abstractDao"&gt;<br />    &lt;property name="proxyInterfaces"&gt;<br />        &lt;value&gt;genericdaotest.dao.PersonDao&lt;/value&gt;<br />    &lt;/property&gt;<br />    &lt;property name="target"&gt;<br />        &lt;bean parent="abstractDaoTarget"&gt;<br />            &lt;constructor-arg&gt;<br />                &lt;value&gt;genericdaotest.domain.Person&lt;/value&gt;<br />            &lt;/constructor-arg&gt;<br />        &lt;/bean&gt;<br />    &lt;/property&gt;<br />&lt;/bean&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 8 中，可以看到使用了这个更新后的 DAO 版本：</p>
		<br />
		<a name="listing8">
				<b>清单 8. 使用类型安全接口</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public void someMethodCreatingAPerson() {<br />    ...<br />    PersonDao dao = (PersonDao)<br />     beanFactory.getBean("personDao"); // This should normally be injected<br /><br />    Person p = new Person("Per", 90);<br />    dao.create(p);<br /><br />    List&lt;Person&gt; result = dao.findByName("Per"); // Runtime exception<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>虽然清单 8 中的代码是使用类型安全 <code><font face="新宋体">PersonDao</font></code> 接口的正确方法，但 DAO 的实现并不完整。调用 <code><font face="新宋体">findByName()</font></code> 会导致运行时异常。问题在于我还没有实现调用 <code><font face="新宋体">findByName()</font></code> 所必需的查询。剩下要做的就是指定查询。为更正该问题，我使用了 Hibernate 命名查询。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1015F">
						<span class="atitle">
								<font face="Arial" size="4">Hibernate 命名查询</font>
						</span>
				</a>
		</p>
		<p>使用 Hibernate，可以在 Hibernate 映射文件 (hbm.xml) 中定义 HQL 查询并为其命名。稍后可以通过简单地引用给定名称来在 Java 代码中使用该查询。该方法的优点之一是能够在部署时优化查询，而无需更改代码。您一会将会看到，另一个优点是无需编写任何新 Java 实现代码，就可以实现 “完整的” DAO。清单 9 是带有命名查询的映射文件的示例：</p>
		<br />
		<a name="listing9">
				<b>清单 9. 带有命名查询的映射文件</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section"> &lt;hibernate-mapping package="genericdaotest.domain"&gt;<br />     &lt;class name="Person"&gt;<br />         &lt;id name="id"&gt;<br />             &lt;generator class="native"/&gt;<br />         &lt;/id&gt;<br />         &lt;property name="name" /&gt;<br />         &lt;property name="weight" /&gt;<br />     &lt;/class&gt;<br /><br />     &lt;query name="Person.findByName"&gt;<br />         &lt;![CDATA[select p from Person p where p.name = ? ]]&gt;<br />     &lt;/query&gt;<br /> &lt;/hibernate-mapping&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 9 定义了域类 <code><font face="新宋体">Person</font></code> 的 Hibernate 映射，该域类具有两个属性：<code><font face="新宋体">name</font></code> 和 <code><font face="新宋体">weight</font></code>。<code><font face="新宋体">Person</font></code> 是具有上述属性的简单 POJO。该文件还包含一个在数据库中查找 <code><font face="新宋体">Person</font></code> 所有实例的查询，其中 “name” 等于提供的参数。Hibernate 不为命名查询提供任何真正的名称空间功能。出于讨论目的，我为所有查询名称都加了域类的短（非限定）名称作为前缀。在现实世界中，使用包括包名称的完全类名可能是更好的主意。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10189">
						<span class="atitle">
								<font face="Arial" size="4">逐步概述</font>
						</span>
				</a>
		</p>
		<p>您已经看到了为任何域对象创建和配置新 DAO 所必需的全部步骤。三个简单的步骤是：</p>
		<ol>
				<li>定义一个接口，它扩展 <code><font face="新宋体">GenericDao</font></code> 并包含所需的任何查找器方法。 
</li>
				<li>将每个查找器的命名查询添加到域对象的 hbm.xml 映射文件。 
</li>
				<li>为 DAO 添加 10 行 Spring 配置文件。 </li>
		</ol>
		<p>查看执行查找器方法的代码（只编写了一次！）来结束我的讨论。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101A5">
						<span class="atitle">
								<font face="Arial" size="4">可重用的 DAO 类</font>
						</span>
				</a>
		</p>
		<p>使用的 Spring advisor 和 interceptor 很简单，事实上它们的工作是向后引用 <code><font face="新宋体">GenericDaoHibernateImplClass</font></code>。方法名以 “find” 打头的所有调用都传递给 DAO 和单个方法 <code><font face="新宋体">executeFinder()</font></code>。</p>
		<br />
		<a name="listing10">
				<b>清单 10. FinderIntroductionAdvisor 的实现</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {<br />    public FinderIntroductionAdvisor() {<br />        super(new FinderIntroductionInterceptor());<br />    }<br />}<br /><br />public class FinderIntroductionInterceptor implements IntroductionInterceptor {<br /><br />    public Object invoke(MethodInvocation methodInvocation) throws Throwable {<br /><br />        FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();<br /><br />        String methodName = methodInvocation.getMethod().getName();<br />        if (methodName.startsWith("find")) {<br />            Object[] arguments = methodInvocation.getArguments();<br />            return genericDao.executeFinder(methodInvocation.getMethod(), arguments);<br />        } else {<br />            return methodInvocation.proceed();<br />        }<br />    }<br /><br />    public boolean implementsInterface(Class intf) {<br />        return intf.isInterface() &amp;&amp; FinderExecutor.class.isAssignableFrom(intf);<br />    }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N101C0">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">executeFinder() 方法</font>
								</strong>
						</span>
				</a>
		</p>
		<p>清单 10 的实现中惟一缺少的是 <code><font face="新宋体">executeFinder()</font></code> 实现。该代码查看调用的类和方法的名称，并使用配置上的约定将其与 Hibernate 查询的名称相匹配。还可以使用 <code><font face="新宋体">FinderNamingStrategy</font></code> 来支持其他命名查询的方法。默认实现查找叫做 “<code><font face="新宋体">ClassName.methodName</font></code>” 的查询，其中 <code><font face="新宋体">ClassName</font></code> 是不带包的短名称。清单 11 完成了泛型类型安全 DAO 实现： </p>
		<br />
		<a name="listing11">
				<b>清单 11. executeFinder() 的实现</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
										</code>
										<pre class="section">public List&lt;T&gt; executeFinder(Method method, final Object[] queryArgs) {<br />     final String queryName = queryNameFromMethod(method);<br />     final Query namedQuery = getSession().getNamedQuery(queryName);<br />     String[] namedParameters = namedQuery.getNamedParameters();<br />     for(int i = 0; i &lt; queryArgs.length; i++) {<br />             Object arg = queryArgs[i];<br />             Type argType =  namedQuery.setParameter(i, arg);<br />      }<br />      return (List&lt;T&gt;) namedQuery.list();<br /> }<br /><br /> public String queryNameFromMethod(Method finderMethod) {<br />     return type.getSimpleName() + "." + finderMethod.getName();<br /> }<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="1" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205555440.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="6" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="8" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<a href="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" target="_blank">
												<img onmousewheel="return bbimg(this)" title="点击在新窗口查看原始图片" height="4" alt="" src="http://www.crackj2ee.com/Article/UploadFiles/200606/20060607205556317.gif" width="100%" onload="java_script_:if(this.width&gt;500)this.width=500" border="0" />
										</a>
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101E3">
						<span class="atitle">
								<font face="Arial" size="4">结束语</font>
						</span>
				</a>
		</p>
		<p>在 Java 5 之前，该语言不支持编写既类型安全<i>又</i> 泛型的代码，您必须只能选择其中之一。在本文中，您已经看到一个结合使用 Java 5 泛型与 Spring 和 Hibernate（以及 AOP）等工具来提高生产率的示例。泛型类型安全 DAO 类相当容易编写 —— 您只需要单个接口、一些命名查询和为 Spring 配置添加的 10 行代码 —— 而且可以极大地减少错误并节省时间。</p>
		<p>几乎本文的所有代码都是可重用的。尽管您的 DAO 类可能包含此处没有实现的查询和操作类型（比如，批操作），但使用我所展示的技术，您至少应该能够实现其中的一部分。参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-genericdao.html#resources"><u><font color="#996699">参考资料</font></u></a> 了解其他泛型类型安全 DAO 类实现。</p>
		<p>
				<a name="N101F6">
						<span class="smalltitle">
								<strong>
										<font face="Arial" size="3">致谢</font>
								</strong>
						</span>
				</a>
		</p>
		<p>自 Java 语言中出现泛型以来，单个泛型类型安全 DAO 的概念已经成为主题。我曾在 JavaOne 2004 中与 Don Smith 简要讨论了泛型 DAO 的灵活性。本文使用的 DAO 实现类旨在作为示例实现，实际上还存在其他实现。例如，Christian Bauer 已经发布了带有 CRUD 操作和标准搜索的实现，Eric Burke 也在该领域做出了工作。我确信将会有更多的实现出现。我要额外感谢 Christian，他目睹了我编写泛型类型安全 DAO 的第一次尝试并提出改进建议。最后，我要感谢 Ramnivas Laddad 的无价帮助，他审阅了本文。</p>
		<br />
<img src ="http://www.blogjava.net/lijiajia418/aggbug/65005.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 10:53 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65005.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的缓存机制介绍</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65003.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 02:52:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65003.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65003.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65003.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65003.html</trackback:ping><description><![CDATA[
		<p>
				<span style="FONT-FAMILY: 宋体">　　缓存是介于应用程序和物理数据源之间，其作用是为了降低应用程序对物理数据源访问的频次，从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制，应用程序在运行时从缓存读写数据，在特定的时刻或事件会同步缓存和物理数据源的数据。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">缓存的介质一般是内存，所以读写速度很快。但如果缓存中存放的数据量非常大时，也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质，还要考虑到管理缓存的并发访问和缓存数据的生命周期。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>Hibernate</span>
				<span style="FONT-FAMILY: 宋体">的缓存包括</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">的缓存和</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的缓存，其中</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的缓存又可以分为两类：内置缓存和外置缓存。</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">的缓存是内置的，不能被卸载，也被称为</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">的第一级缓存。</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的内置缓存和</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">的缓存在实现方式上比较相似，前者是</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">对象的一些集合属性包含的数据，后者是指</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">的一些集合属性包含的数据。</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的内置缓存中存放了映射元数据和预定义</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体">语句，映射元数据是映射文件中数据的拷贝，而预定义</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体">语句是在</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">初始化阶段根据映射元数据推导出来，</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的内置缓存是只读的，应用程序不能修改缓存中的映射元数据和预定义</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体">语句，因此</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">不需要进行内置缓存与映射文件的同步。</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的外置缓存是一个可配置的插件。在默认情况下，</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">不会启用这个插件。外置缓存的数据是数据库数据的拷贝，外置缓存的介质可以是内存或者硬盘。</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">的外置缓存也被称为</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">的第二级缓存。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>Hibernate</span>
				<span style="FONT-FAMILY: 宋体">的这两级缓存都位于持久化层，存放的都是数据库数据的拷贝，那么它们之间的区别是什么呢？为了理解二者的区别，需要深入理解持久化层的缓存的两个特性：缓存的范围和缓存的并发访问策略。</span>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">持久化层的缓存的范围</span>
				</b>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>1 </span>
				<span style="FONT-FAMILY: 宋体">事务范围：缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期，当事务结束时，缓存也就结束生命周期。在此范围下，缓存的介质是内存。事务可以是数据库事务或者应用事务，每个事务都有独自的缓存，缓存内的数据通常采用相互关联的的对象形式。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>2 </span>
				<span style="FONT-FAMILY: 宋体">进程范围：缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存，因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期，进程结束时，缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据，所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据，但是对象分解为松散的算法比对象序列化的算法要求更快。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>3 </span>
				<span style="FONT-FAMILY: 宋体">集群范围：在集群环境中，缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点，进程间通过远程通信来保证缓存中的数据的一致性，缓存中的数据通常采用对象的松散数据形式。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">对大多数应用来说，应该慎重地考虑是否需要使用集群范围的缓存，因为访问的速度不一定会比直接访问数据库数据的速度快多少。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据，还可以到进程范围或集群范围的缓存内查询，如果还是没有查到，那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存，通常它是必需的；进程范围或集群范围的缓存是持久化层的第二级缓存，通常是可选的。</span>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">持久化层的缓存的并发访问策略</span>
				</b>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">当多个并发的事务同时访问持久化层的缓存的相同数据时，会引起并发问题，必须采用必要的事务隔离措施。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">在进程范围或集群范围的缓存，即第二级缓存，会出现并发问题。因此可以设定以下四种类型的并发访问策略，每一种策略对应一种事务隔离级别。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">事务型：仅仅在受管理环境中适用。它提供了</span>
				<span lang="EN-US">Repeatable Read</span>
				<span style="FONT-FAMILY: 宋体">事务隔离级别。对于经常被读但很少修改的数据，可以采用这种隔离类型，因为它可以防止脏读和不可重复读这类的并发问题。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">读写型：提供了</span>
				<span lang="EN-US">Read Committed</span>
				<span style="FONT-FAMILY: 宋体">事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据，可以采用这种隔离类型，因为它可以防止脏读这类的并发问题。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">非严格读写型：不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能，必须为该数据配置一个很短的数据过期时间，从而尽量避免脏读。对于极少被修改，并且允许偶尔脏读的数据，可以采用这种并发访问策略。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">只读型：对于从来不会修改的数据，如参考数据，可以使用这种并发访问策略。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">事务型并发访问策略是事务隔离级别最高，只读型的隔离级别最低。事务隔离级别越高，并发性能就越低。</span>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">什么样的数据适合存放到第二级缓存中？</span>
				</b>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">1 </span>
				</b>
				<span style="FONT-FAMILY: 宋体">很少被修改的数据</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<strong>2 </strong>
				</span>
				<span style="FONT-FAMILY: 宋体">不是很重要的数据，允许出现偶尔并发的数据</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<strong>3</strong>
				</span>
				<span style="FONT-FAMILY: 宋体">不会被并发访问的数据</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<strong>4</strong>
				</span>
				<span lang="EN-US" style="FONT-FAMILY: Wingdings">
						<span>
								<span>
								</span>
						</span>
				</span>
				<span style="FONT-FAMILY: 宋体">参考数据</span>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">不适合存放到第二级缓存的数据？</span>
				</b>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">1 </span>
				</b>
				<span style="FONT-FAMILY: 宋体">经常被修改的数据</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<strong>2 </strong>
				</span>
				<span style="FONT-FAMILY: 宋体">财务数据，绝对不允许出现并发</span>
		</p>
		<p>
				<span style="FONT-FAMILY: 宋体">
						<strong>3</strong>
				</span>
				<span style="FONT-FAMILY: 宋体">与其他应用共享的数据。</span>
		</p>
		<p>
				<b>
						<span lang="EN-US">Hibernate</span>
				</b>
				<b>
						<span style="FONT-FAMILY: 宋体">的二级缓存</span>
				</b>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">如前所述，</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">提供了两级缓存，第一级是</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">的缓存。由于</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">对象的生命周期通常对应一个数据库事务或者一个应用事务，因此它的缓存是事务范围的缓存。第一级缓存是必需的，不允许而且事实上也无法比卸除。在第一级缓存中，持久化类的每个实例都具有唯一的</span>
				<span lang="EN-US">OID</span>
				<span style="FONT-FAMILY: 宋体">。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>
				</span>
				<span style="FONT-FAMILY: 宋体">第二级缓存是一个可插拔的的缓存插件，它是由</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">负责管理。由于</span>
				<span lang="EN-US">SessionFactory</span>
				<span style="FONT-FAMILY: 宋体">对象的生命周期和应用程序的整个过程对应，因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题，因此需要采用适当的并发访问策略，该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">集成。第二级缓存是可选的，可以在每个类或每个集合的粒度上配置第二级缓存。</span>
		</p>
		<p>
				<b>
						<span lang="EN-US">Hibernate</span>
				</b>
				<b>
						<span style="FONT-FAMILY: 宋体">的二级缓存策略的一般过程如下：</span>
				</b>
		</p>
		<p>
				<b>
						<span style="FONT-FAMILY: 宋体">
						</span>
				</b>
				<span lang="EN-US">
						<span>1)<span></span></span>
				</span>
				<span style="FONT-FAMILY: 宋体">条件查询的时候，总是发出一条</span>
				<span lang="EN-US">select * from table_name where …. </span>
				<span style="FONT-FAMILY: 宋体">（选择所有字段）这样的</span>
				<span lang="EN-US">SQL</span>
				<span style="FONT-FAMILY: 宋体">语句查询数据库，一次获得所有的数据对象。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>2)<span></span></span>
				</span>
				<span style="FONT-FAMILY: 宋体">把获得的所有数据对象根据</span>
				<span lang="EN-US">ID</span>
				<span style="FONT-FAMILY: 宋体">放入到第二级缓存中。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>3)<span></span></span>
				</span>
				<span style="FONT-FAMILY: 宋体">当</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">根据</span>
				<span lang="EN-US">ID</span>
				<span style="FONT-FAMILY: 宋体">访问数据对象的时候，首先从</span>
				<span lang="EN-US">Session</span>
				<span style="FONT-FAMILY: 宋体">一级缓存中查；查不到，如果配置了二级缓存，那么从二级缓存中查；查不到，再查询数据库，把结果按照</span>
				<span lang="EN-US">ID</span>
				<span style="FONT-FAMILY: 宋体">放入到缓存。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>4)<span></span></span>
				</span>
				<span style="FONT-FAMILY: 宋体">删除、更新、增加数据的时候，同时更新缓存。</span>
		</p>
		<p>
				<span lang="EN-US">
						<span>　　</span>Hibernate</span>
				<span style="FONT-FAMILY: 宋体">的二级缓存策略，是针对于</span>
				<span lang="EN-US">ID</span>
				<span style="FONT-FAMILY: 宋体">查询的缓存策略，对于条件查询则毫无作用。为此，</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">提供了针对条件查询的</span>
				<span lang="EN-US">Query</span>
				<span style="FONT-FAMILY: 宋体">缓存。</span>
		</p>
		<p>
				<strong>
						<span lang="EN-US">Hibernate</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">的</span>
						<span lang="EN-US">Query</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">缓存策略的过程如下：</span>
				</strong>
		</p>
		<p>
				<strong>
						<span style="FONT-FAMILY: 宋体">
						</span>
				</strong>
				<span lang="EN-US">
						<span>1)<span><font size="3"></font></span></span>
				</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">首先根据这些信息组成一个</span>
				<span lang="EN-US">Query Key</span>
				<span style="FONT-FAMILY: 宋体">，</span>
				<span lang="EN-US">Query Key</span>
				<span style="FONT-FAMILY: 宋体">包括条件查询的请求一般信息：</span>
				<span lang="EN-US">SQL, SQL</span>
				<span style="FONT-FAMILY: 宋体">需要的参数，记录范围（起始位置</span>
				<span lang="EN-US">rowStart</span>
				<span style="FONT-FAMILY: 宋体">，最大记录个数</span>
				<span lang="EN-US">maxRows)</span>
				<span style="FONT-FAMILY: 宋体">，等。</span>
				<span lang="EN-US">
				</span>
		</p>
		<p>
				<span lang="EN-US">
				</span>
				<span lang="EN-US">
						<span>2)<span><font size="3"></font></span></span>
				</span>
				<span lang="EN-US">Hibernate</span>
				<span style="FONT-FAMILY: 宋体">根据这个</span>
				<span lang="EN-US">Query Key</span>
				<span style="FONT-FAMILY: 宋体">到</span>
				<span lang="EN-US">Query</span>
				<span style="FONT-FAMILY: 宋体">缓存中查找对应的结果列表。如果存在，那么返回这个结果列表；如果不存在，查询数据库，获取结果列表，把整个结果列表根据</span>
				<span lang="EN-US">Query Key</span>
				<span style="FONT-FAMILY: 宋体">放入到</span>
				<span lang="EN-US">Query</span>
				<span style="FONT-FAMILY: 宋体">缓存中。</span>
		</p>
		<p>
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">
								<strong>3) </strong>Query Key</span>
						<span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">中的</span>
						<span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">SQL</span>
						<span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">涉及到一些表名，如果这些表的任何数据发生修改、删除、增加等操作，这些相关的</span>
						<span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">Query Key</span>
						<span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">都要从缓存中清空。</span>
				</font>
		</p>
<img src ="http://www.blogjava.net/lijiajia418/aggbug/65003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 10:52 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate----自定义数据类型</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65002.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65002.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65002.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65002.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65002.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<div class="postcontent">
												<p>package org.william.First;</p>
												<p>
														<br />import org.hibernate.usertype.*;<br />import java.io.Serializable;<br />import java.sql.Types;<br />import java.util.List;<br />import java.util.ArrayList;<br />import java.util.Vector;<br />import org.hibernate.type.*;<br />import org.hibernate.*;</p>
												<p>import javax.sql.*;<br />import java.sql.*;</p>
												<p>/**<br /> * @author wangliang138840<br /> *<br /> */<br />public class EMailList implements UserType{<br /> private List eMails;<br /> private static final char SPLITE = ';';<br /> //各个字段的类型<br /> public static final int[] TYPES = new int[]{Types.VARCHAR };<br /> //本实例是否可变<br /> public boolean isMutable(){<br />  return false;<br /> }<br /> //返回字段类型<br /> public int[] sqlTypes(){<br />  return TYPES;<br /> }<br /> //返回字段类型类<br /> public Class returnedClass(){<br />  return List.class;<br /> }<br /> /* (non-Javadoc)<br />  * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)<br />  * 完全拷贝一个变量实体；<br />  */<br /> public Object deepCopy(Object value) throws HibernateException{<br />  List targetList = new ArrayList();<br />  if(value == null)return targetList;<br />  List sourceList = (List)value;<br />  targetList.addAll(sourceList);<br />  return targetList;<br /> }<br /> /* (non-Javadoc)<br />  * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)<br />  * 判断两个实体是否相等<br />  */<br /> public boolean equals(Object x, Object y) throws HibernateException{<br />  if( x == y) return true;<br />  if(x != null &amp;&amp; y != null){<br />   List listX = (List)x;<br />   List listY = (List)y;<br />   if(listX.size() != listY.size()) return false;<br />   for(int i = 0; i&lt; listX.size(); i++){<br />    String str1 = (String)listX.get(i);<br />    String str2 = (String)listY.get(i);<br />    if(!equals(str1,str2)) return false;<br />   }<br />   return true;<br />  }<br />  return false;<br /> }<br /> <br /> public int hashCode(Object x)<br />  throws HibernateException{<br />  return -1;<br /> }<br /> public Object nullSafeGet(ResultSet rs, String[] names, Object owner)<br />  throws HibernateException, SQLException{<br />  String value = (String)Hibernate.STRING.nullSafeGet(rs, names[0]);<br />  if(value != null)return db2oo(value);<br />  else return new ArrayList();<br /> }<br /> <br /> /* (non-Javadoc)<br />  * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)<br />  */<br /> public void nullSafeSet(PreparedStatement st, Object value, int index)<br />  throws HibernateException, SQLException{<br />  if(value != null){<br />   Object str = oo2db(value);<br />   Hibernate.STRING.nullSafeSet(st, str, index);<br />  }else{<br />   Hibernate.STRING.nullSafeSet(st, value, index);<br />  }<br /> }<br /> <br /> /**<br />  * @param value<br />  * @return<br />  */<br /> private Object oo2db(Object value){<br />  StringBuffer strBuf = new StringBuffer();<br />  List list = (List)value;<br />  for(int i = 0; i&lt;list.size() -1; i++){<br />   strBuf.append(list.get(i)).append(SPLITE);<br />  }<br />  strBuf.append(list.get(list.size()-1));<br />  return (Object)strBuf.toString();<br /> }<br /> <br /> /**<br />  * @param value<br />  * @return<br />  */<br /> private List db2oo(String value){<br />  Vector strs = org.apache.tools.ant.util.StringUtils.split(value, SPLITE);<br />  List emailList = new ArrayList();<br />  for(int i = 0; i&lt;strs.size(); i++){<br />   emailList.add(strs.get(i));<br />  }<br />  return emailList;<br /> }</p>
												<p> /* (non-Javadoc)<br />  * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)<br />  */<br /> public Object assemble(Serializable cached, Object owner)<br />  throws HibernateException{<br />  return cached;<br /> }<br /> <br /> public Serializable disassemble(Object value)<br />  throws HibernateException{<br />  return (Serializable)value;<br /> }<br /> <br /> public Object replace(Object original, Object target, Object owner)<br />  throws HibernateException{<br />  return null;<br /> }<br /> <br />}</p>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/lijiajia418/aggbug/65002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 10:51 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的事务和并发(ZT)</title><link>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65001.html</link><dc:creator>Binary</dc:creator><author>Binary</author><pubDate>Tue, 22 Aug 2006 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65001.html</guid><wfw:comment>http://www.blogjava.net/lijiajia418/comments/65001.html</wfw:comment><comments>http://www.blogjava.net/lijiajia418/archive/2006/08/22/65001.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lijiajia418/comments/commentRss/65001.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lijiajia418/services/trackbacks/65001.html</trackback:ping><description><![CDATA[
		<a>Hibernate的事务和并发控制很容易掌握。Hibernate直接使用JDBC连接和JTA资源，不添加任何附加锁定行为。我们强烈推荐你花点时间了解JDBC编程，ANSI SQL查询语言和你使用的数据库系统的事务隔离规范。Hibernate只添加自动版本管理，而不会锁 定内存中的对象，也不会改变数据库事务的隔离级别。基本上，使用 Hibernate就好像直接使用JDBC(或者JTA/CMT)来访问你的数据库资源。<br /><br /></a> 除了自动版本管理，针对行级悲观锁定，Hibernate也提供了辅助的API，它使用了 SELECT FOR UPDATE的SQL语法。本章后面会讨论这个API。 <br />我们从Configuration层、SessionFactory层, 和 Session层开始讨论Hibernate的并行控制、<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务和应用 程序的长事务。 <br /><br /><strong>12.1.Session和事务范围(transaction scopes)</strong><br />一个SessionFactory对象的创建代价很昂贵，它是线程<a href="http://www.gamvan.com/server/" target="_blank">安全</a>的对象，它被设计成可以 为所有的应用程序线程所共享。它只创建一次，通常是在应用程序启动的时候，由一个 Configuraion的实例来创建。 <br />一个Session的对象是轻型的，非线程<a href="http://www.gamvan.com/server/" target="_blank">安全</a>的，对于单个业务进程，单个的 工作单元而言，它只被使用一次，然后就丢弃。只有在需要的时候，Session 才会获取一个JDBC的Connection（或一个Datasource）对象。所以你可以放心的打开和关闭Session，甚至当你并不确定一个特定的请求是否需要数据访问时，你也可以这样做。(一旦你实现下面提到的使用了请求拦截的模式，这就 变得很重要了。 <br />此外我们还要考虑<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务。<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务应该尽可能的短，降低<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>锁定造成的资源争用。 <a href="http://www.gamvan.com/database/" target="_blank">数据库</a>长事务会导致你的应用程序无法扩展到高的并发负载。 <br />一个操作单元(Unit of work)的范围是多大？单个的Hibernate Session能跨越多个 <a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务吗？还是一个Session的作用范围对应一个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务的范围？应该何时打开 Session，何时关闭Session？，你又如何划分<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务的边界呢？ <br /><br /><strong>12.1.1.操作单元(Unit of work)</strong><br />首先，别再用session-per-operation这种反模式了，也就是说，在单个线程中， 不要因为一次简单的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>调用，就打开和关闭一次Session！<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务也是如此。 应用程序中的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>调用是按照计划好的次序，分组为原子的操作单元。（注意，这也意味着，应用程序中，在单个的SQL语句发送之后，自动事务提交(auto-commit)模式失效了。这种模式专门为SQL控制台操作设计的。 Hibernate禁止立即自动事务提交模式，或者期望应用服务器禁止立即自动事务提交模式。） <br />在多用户的client/server应用程序中，最常用的模式是 每个请求一个会话(session-per-request)。在这种模式下，来自客户端的请求被发送到服务器端（即Hibernate持久化层运行的地方），一 个新的Hibernate Session被打开，并且执行这个操作单元中所有的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>操作。 一旦操作完成（同时发送到客户端的响应也准备就绪），session被同步，然后关闭。你也可以使用单 个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务来处理客户端请求，在你打开Session之后启动事务，在你关闭 Session之前提交事务。会话和请求之间的关系是一对一的关系，这种模式对 于大多数应用程序来说是很棒的。 <br />真正的挑战在于如何去实现这种模式：不仅Session和事务必须被正确的开始和结束，而且他们也必须能被数据访问操作访问。用拦截器来实现操作单元的划分，该拦截器在客户端请求达到服务器端的时候开始，在服务器端发送响应（即，ServletFilter）之前结束。我们推荐 使用一个ThreadLocal 变量，把 Session绑定到处理客户端请求的线 程上去。这种方式可以让运行在该线程上的所有程序代码轻松的访问Session（就像访问一个静态变量那样）。你也可以在一个ThreadLocal 变量中保持事务上下文环境，不过这依赖 于你所选择的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务划分机制。这种实现模式被称之为 ThreadLocal Session和 Open Session in View。你可以很容易的扩展本文前面章节展示的 HibernateUtil 辅助类来实现这种模式。当然，你必胝业揭恢质迪掷菇仄鞯姆椒ǎ?且可以把拦截器集成到你的应用环境中。请参考Hibernate<a href="http://www.gamvan.com/web/" target="_blank">网站</a>上面的提示和例子。 <br /><br /><strong>12.1.2.应用程序事务(Application transactions)</strong><br />session-per-request模式不仅仅是一个可以用来设计操作单元的有用概念。很多业务处理流程都需 要一系列完整的和用户之间的交互，即用户对<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>的交叉访问。在基于web的应用和企业 应用中，跨用户交互的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务是无法接受的。考虑下面的例子： <br />在界面的第一屏，打开对话框，用户所看到的数据是被一个特定的 Session 和数据 库事务载入(load)的。用户可以随意修改对话框中的数据对象。 <br />5分钟后，用户点击“保存”，期望所做出的修改被持久化；同时他也期望自己是唯一修改这个信息的人，不会出现 修改冲突。 <br />从用户的角度来看，我们把这个操作单元称为应用程序长事务（application transaction）。 在你的应用程序中，可以有很多种方法来实现它。 <br />头一个幼稚的做法是，在用户思考的过程中，保持Session和<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务是打开的， 保持<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>锁定，以阻止并发修改，从而保证<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务隔离级别和原子操作。这种方式当然是一个反模式， 因为<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>锁定的维持会导致应用程序无法扩展并发用户的数目。 <br />很明显，我们必须使用多个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务来实现一个应用程序事务。在这个例子中，维护业务处理流程的 事务隔离变成了应用程序层的部分责任。单个应用程序事务通常跨越多个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务。如果仅仅只有一 个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务（最后的那个事务）保存更新过的数据，而所有其他事务只是单纯的读取数据（例如在一 个跨越多个请求/响应周期的向导风格的对话框中），那么应用程序事务将保证其原子性。这种方式比听 起来还要容易实现，特别是当你使用了Hibernate的下述特性的时候： <br />自动版本化 - Hibernate能够自动进行乐观并发控制 ，如果在用户思考 的过程中发生并发修改冲突，Hibernate能够自动检测到。 <br />脱管对象（Detached Objects）- 如果你决定采用前面已经讨论过的 session-per-request模式，所有载入的实例在用户思考的过程中都处于与Session脱离的状态。Hibernate允许你把与Session脱离的对象重新关联到Session 上，并且对修改进行持久化，这种模式被称为 session-per-request-with-detached-objects。自动版本化被用来隔离并发修改。 <br />长生命周期的Session （Long Session）- Hibernate 的Session 可以在<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务提交之后和底层的JDBC连接断开，当一个新的客户端请求到来的时候，它又重新连接上底层的 JDBC连接。这种模式被称之为session-per-application-transaction，这种情况可能会造成不必要的Session和JDBC连接的重新关联。自动版本化被用来隔离并发修改。 <br />session-per-request-with-detached-objects 和 session-per-application-transaction 各有优缺点，我们在本章后面乐观并发 控制那部分再进行讨论。 <br /><br /><strong>12.1.3.关注对象标识(Considering object identity)</strong><br />应用程序可能在两个不同的Session中并发访问同一持久化状态，但是， 一个持久化类的实例无法在两个 Session中共享。因此有两种不同的标识语义： <br /><a href="http://www.gamvan.com/database/" target="_blank">数据库</a>标识 <br />foo.getId().equals( bar.getId() ) <br />JVM 标识 <br />foo==bar <br />对于那些关联到 特定Session （也就是在单个Session的范围内）上的对象来说，这 两种标识的语义是等价的，与<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>标识对应的JVM标识是由Hibernate来保 证的。不过，当应用程序在两个不同的session中并发访问具有同一持久化标识的业务对象实例的时候，这个业务对象的两个实例事实上是不相同的（从 JVM识别来看）。这种冲突可以通过在同步和提交的时候使用自动版本化和乐观锁定方法来解决。 <br />这种方式把关于并发的头疼问题留给了Hibernate和<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>；由于在单个线程内，操作单元中的对象识别不 需要代价昂贵的锁定或其他意义上的同步，因此它同时可以提供最好的可伸缩性。只要在单个线程只持有一个 Session，应用程序就不需要同步任何业务对象。在Session 的范围内，应用程序可以放心的使用==进行对象比较。 <br />不过，应用程序在Session的外面使用==进行对象比较可能会 导致无法预期的结果。在一些无法预料的场合，例如，如果你把两个脱管对象实例放进同一个 Set的时候，就可能发生。这两个对象实例可能有同一个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>标识（也就是说， 他们代表了表的同一行数据），从JVM标识的定义上来说，对脱管的对象而言，Hibernate无法保证他们的的JVM标识一致。开发人员必须覆盖持久化类的equals()方法和 hashCode() 方法，从而实现自定义的对象相等语义。警告：不要使用<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>标识 来实现对象相等，应该使用业务键值，由唯一的，通常不变的属性组成。当一个瞬时对象被持久化的时 候，它的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>标识会发生改变。如果一个瞬时对象（通常也包括脱管对象实例）被放入一 个Set，改变它的hashcode会导致与这个Set的关系中断。虽 然业务键值的属性不象<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>主键那样稳定不变，但是你只需要保证在同一个Set 中的对象属性的稳定性就足够了。请到Hibernate<a href="http://www.gamvan.com/web/" target="_blank">网站</a>去寻求这个问题更多的详细的讨论。请注意，这不是一 个有关Hibernate的问题，而仅仅是一个关于Java对象标识和判等行为如何实现的问题。 <br /><br /><strong>12.1.4.常见问题</strong><br />决不要使用反模式session-per-user-session或者 session-per-application（当然，这个规定几乎没有例外）。请注意，下述一些问题可能也会出现在我们推荐的模式中，在你作出某个设计决定之前，请务必理解该模式的应用前提。 <br />Session 是一个非线程<a href="http://www.gamvan.com/server/" target="_blank">安全</a>的类。如果一个Session 实例允许共享的话，那些支持并发运行的东东，例如HTTP request，session beans,或者是 Swing workers，将会导致出现资源争用（race condition）。如果在HttpSession中有 Hibernate 的Session的话（稍后讨论），你应该考虑同步访问你的Http session。否则，只要用户足够快的点击浏览器的“刷新”，就会导致两个并发运行线程使用同一个 Session。 <br />一个由Hibernate抛出的异常意味着你必须立即回滚<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务，并立即关闭Session （稍后会展开讨论）。如果你的Session绑定到一个应用程序上，你必 须停止该应用程序。回滚<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务并不会把你的业务对象退回到事务启动时候的状态。这 意味着<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>状态和业务对象状态不同步。通常情况下，这不是什么问题，因为异常是不可 恢复的,你必须在回滚之后重新开始执行。 <br />Session 缓存了处于持久化状态的每个对象（Hibernate会监视和检查脏数据）。这意味着，如果你让Session打开很长一段时间，或是仅仅载入了过多的数据， Session占用的内存会一直增长，直到抛出OutOfMemoryException异常。这个 问题的一个解决方法是调用clear() 和evict()来管理 Session的缓存，但是如果你需要大批量数据操作的话，最好考虑 使用存储过程。在第14章 批量处理（Batch processing）中有一些解决方案。在用户会话期间一直保持 Session打开也意味着出现脏数据的可能性很高。 <br /><br /><strong>12.2.<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务声明</strong><br /><a href="http://www.gamvan.com/database/" target="_blank">数据库</a>（或者系统）事务的声明总是必须的。在<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务之外，就无法和<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>通讯（这可能会让那些习惯于 自动提交事务模式的开发人员感到迷惑）。永远使用清晰的事务声明，即使只读操作也是如此。进行 显式的事务声明并不总是需要的，这取决于你的事务隔离级别和<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>的能力，但不管怎么说，声明事务总归有益无害。 <br />一个Hibernate应用程序可以运行在非托管环境中（也就是独立运行的应用程序，简单Web应用程序， 或者Swing图形桌面应用程序），也可以运行在托管的J2EE环境中。在一个非托管环境中，Hibernate 通常自己负责管理<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>连接池。应用程序开发人员必须手工设置事务声明，换句话说，就是手工启 动，提交，或者回滚<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务。一个托管的环境通常提供了容器管理事务，例如事务装配通过可声 明的方式定义在EJB session beans的部署描述符中。可编程式事务声明不再需要，即使是 Session 的同步也可以自动完成。 <br />让持久层具备可移植性是人们的理想。Hibernate提供了一套称为Transaction的封装API，用来把你的部署环境中的本地事务管理系统转换到Hibernate事务上。这个API是可选的，但是我们强烈 推荐你使用，除非你用CMT session bean。 <br />通常情况下，结束 Session 包含了四个不同的阶段: <br />同步session(flush,刷出到磁盘） <br />提交事务 <br />关闭session <br />处理异常 <br />session的同步(flush,刷出）前面已经讨论过了，我们现在进一步考察在托管和非托管环境下的事务声明和异常处理。 <br /><br /><strong>12.2.1.非托管环境</strong><br />如果Hibernat持久层运行在一个非托管环境中，<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>连接通常由Hibernate的连接池机制 来处理。 <br /><br /><br /><br /><table style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-BOTTOM-WIDTH: 1px; BORDER-RIGHT-WIDTH: 1px" bordercolor="#e0e0e0" cellspacing="1" cellpadding="4" width="95%" align="center" border="1" table-layout="" fixed=""><tbody><tr><td style="HEIGHT: 25px" valign="top" bgcolor="#f6f6f6"><font style="COLOR: rgb(176,176,176)">代码内容</font><br />session/transaction处理方式如下所示： <br />//Non-managed environment idiom <br />Session sess = factory.openSession(); <br />Transaction tx = null; <br />try { <br />tx = sess.beginTransaction(); <br /><br />// do some work <br />... <br /><br />tx.commit(); <br />} <br />catch (RuntimeException e) { <br />if (tx != null) tx.rollback(); <br />throw e; // or display error message <br />} <br />finally { <br />sess.close(); <br />} </td></tr></tbody></table><br />你不需要显式flush() Session - 对commit()的调用会自动触发session的同步。 <br />调用 close() 标志session的结束。 close()方法重要的暗示是，session释放了JDBC连接。 <br />这段Java代码是可移植的，可以在非托管环境和JTA环境中运行。 <br />你很可能从未在一个标准的应用程序的业务代码中见过这样的用法；致命的（系统）异常应该总是在应用程序“顶层”被捕获。换句话说，执行Hibernate调用的代码（在持久层）和处理 RuntimeException异常的代码（通常只能清理和退出应用程序）应该在不同的应用程序逻辑层。这对于你设计自己的软件系统来说是一个挑战，只要有可能，你就应该使用 J2EE/EJB容器服务。异常处理将在本章稍后进行讨论。 <br />请注意，你应该选择 org.hibernate.transaction.JDBCTransactionFactory (这是默认选项). <br /><br /><strong>12.2.2.使用JTA</strong><br />如果你的持久层运行在一个应用服务器中（例如，在EJB session beans的后面），Hibernate获取 的每个数据源连接将自动成为全局JTA事务的一部分。Hibernate提供了两种策略进行JTA集成。 <br />如果你使用bean管理事务（BMT），可以通过使用Hibernate的 Transaction API来告诉 应用服务器启动和结束BMT事务。因此，事务管理代码和在非托管环境下是一样的。 <br /><br /><br /><br /><br /><table style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-BOTTOM-WIDTH: 1px; BORDER-RIGHT-WIDTH: 1px" bordercolor="#e0e0e0" cellspacing="1" cellpadding="4" width="95%" align="center" border="1" table-layout="" fixed=""><tbody><tr><td style="HEIGHT: 25px" valign="top" bgcolor="#f6f6f6"><font style="COLOR: rgb(176,176,176)">代码内容</font><br />// BMT idiom <br />Session sess = factory.openSession(); <br />Transaction tx = null; <br />try { <br />tx = sess.beginTransaction(); <br /><br />// do some work <br />... <br /><br />tx.commit(); <br />} <br />catch (RuntimeException e) { <br />if (tx != null) tx.rollback(); <br />throw e; // or display error message <br />} <br />finally { <br />sess.close(); <br />} </td></tr></tbody></table>在CMT 方式下，事务声明是在session bean的部署描述符中，而不需要编程。除非你设置了属性hibernate.transaction.flush_before_completion和 hibernate.transaction.auto_close_session为true，否则你必须自己同步和关闭Session。Hibernate可以为你自动同步和关闭 Session。你唯一要做的就是当发生异常时进行事务回滚。幸运的是， 在一个CMT bean中，事务回滚甚至可以由容器自动进行，因为由session bean方法抛出的未处理的 RuntimeException异常可以通知容器设置全局事务回滚。这意味着在CMT中，你完全无需使用Hibernate的Transaction API 。 <br />请注意，当你配置Hibernate事务工厂的时候，在一个BMT session bean中，你应该选择 org.hibernate.transaction.JTATransactionFactory，在一个 CMT session bean中选择org.hibernate.transaction.CMTTransactionFactory。记住，同时也要设置org.hibernate.transaction.manager_lookup_class。 <br />如果你使用CMT环境，并且让容器自动同步和关闭session，你可能也希望在你代码的不同部分使用同一个session。一般来说，在一个非托管环境中，你可以使用一个ThreadLocal 变量来持有这个session，但是单个EJB方法调用可能会在不同的线程中执行（举例来说，一个session bean调用另一个session bean）。如果你不想在应用代码中被传递Session对 象实例的问题困扰的话，那么SessionFactory 提供的 getCurrentSession()方法就很适合你，该方法返回一个绑定到JTA事务上下文环境中的session实例。这也是把Hibernate集成到一个应用程序中的最简单的方法！这个“当前的”session总是可以自动同步和自动关闭（不考虑上述的属性设置）。我们的session/transaction 管理代码减少到如下所示： <br /><br /><br /><br /><br /><table style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-BOTTOM-WIDTH: 1px; BORDER-RIGHT-WIDTH: 1px" bordercolor="#e0e0e0" cellspacing="1" cellpadding="4" width="95%" align="center" border="1" table-layout="" fixed=""><tbody><tr><td style="HEIGHT: 25px" valign="top" bgcolor="#f6f6f6"><font style="COLOR: rgb(176,176,176)">代码内容</font><br />// CMT idiom <br />Session sess = factory.getCurrentSession(); <br /><br />// do some work <br />... </td></tr></tbody></table><br />换句话来说，在一个托管环境下，你要做的所有的事情就是调用 SessionFactory.getCurrentSession()，然后进行你的数据访问，把其余的工作交给容器来做。事务在你的session bean的部署描述符中以可声明的方式来设置。session的生命周期完全 由Hibernate来管理。 <br />对after_statement连接释放方式有一个警告。因为JTA规范的一个很愚蠢的限制，Hibernate不可能自动清理任何未关闭的 ScrollableResults 或者Iterator，它们是由scroll()或iterate()产生的。你must通过在finally块中，显式调用 ScrollableResults.close()或者Hibernate.close(Iterator)方法来释放底层<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>游标。(当然，大部分程序完全可以很容易的避免在CMT代码中出现scroll()或iterate()。) <br /><br /><strong>12.2.3.异常处理</strong><br />如果 Session 抛出异常 (包括任何SQLException), 你应该立即回滚<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务，调用 Session.close() ，丢弃该 Session实例。Session的某些方法可能会导致session 处于不一致的状态。所有由Hibernate抛出的异常都视为不可以恢复的。确保在 finally 代码块中调用close()方法，以关闭掉 Session。 <br />HibernateException是一个非检查期异常（这不同于Hibernate老的版本），它封装了Hibernate持久层可能出现的大多数错误。我们的观点是，不应该强迫应用程序开发人员在底层捕获无法恢复的异常。在大多数软件系统中，非检查期异常和致命异常都是在相应方法调用的堆栈的顶层被处理的（也就是说，在软件上面的逻辑层），并且提供一个错误信息给应用软件的用户（或者采取其他某些相应的操作）。请注意，Hibernate也有可能抛出其他并不属于 HibernateException的非检查期异常。这些异常同样也是无法恢复的，应该 采取某些相应的操作去处理。 <br />在和<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>进行交互时，Hibernate把捕获的SQLException封装为Hibernate的 JDBCException。事实上，Hibernate尝试把异常转换为更有实际含义的JDBCException异常的子类。底层的SQLException可以通过JDBCException.getCause()来得到。Hibernate通过使用关联到 SessionFactory上的SQLExceptionConverter来把SQLException转换为一个对应的JDBCException 异常的子类。默认情况下，SQLExceptionConverter可以通过配置dialect 选项指定；此外，也可以使用用户自定义的实现类（参考javadocs SQLExceptionConverterFactory类来了解详情）。标准的 JDBCException子类型是： <br />JDBCConnectionException - 指明底层的JDBC通讯出现错误 <br />SQLGrammarException - 指明发送的SQL语句的语法或者格式错误 <br />ConstraintViolationException - 指明某种类型的约束违例错误 <br />LockAcquisitionException - 指明了在执行请求操作时，获取 所需的锁级别时出现的错误。 <br />GenericJDBCException - 不属于任何其他种类的原生异常 <br /><br /><strong>12.3.乐观并发控制(Optimistic concurrency control)</strong><br />唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、或者时间戳来检测更新冲突（并且防止更新丢失）。Hibernate为使用乐观并发控制的代码提供了三种可能的方法，应用程序在编写这些代码时，可以采用它们。我们已经在前面应用程序长事务那部分展示了 乐观并发控制的应用场景，此外，在单个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务范围内，版本检查也提供了防止更新丢失的好处。 <br />12.3.1.应用程序级别的版本检查(Application version checking) <br />未能充分利用Hibernate功能的实现代码中，每次和<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>交互都需要一个新的 Session，而且开发人员必须在显示数据之前从<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>中重 新载入所有的持久化对象实例。这种方式迫使应用程序自己实现版本检查来确保 应用程序事务的隔离，从数据访问的角度来说是最低效的。这种使用方式和 entity EJB最相似。 <br />// foo is an instance loaded by a previous Session <br />session = factory.openSession(); <br />Transaction t = session.beginTransaction(); <br />int oldVersion = foo.getVersion(); <br />session.load( foo, foo.getKey() ); // load the current state <br />if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException(); <br />foo.setProperty("bar"); <br />t.commit(); <br />session.close(); <br />version 属性使用 来映射，如果对象 是脏数据，在同步的时候，Hibernate会自动增加版本号。 <br />当然，如果你的应用是在一个低数据并发环境下，并不需要版本检查的话，你照样可以使用 这种方式，只不过跳过版本检查就是了。在这种情况下，最晚提交生效（last commit wins）就是你的应用程序长事务的默认处理策略。请记住这种策略可能会让应用软件的用户感到困惑，因为他们有可能会碰上更新丢失掉却没 有出错信息，或者需要合并更改冲突的情况。 <br />很明显，手工进行版本检查只适合于某些软件规模非常小的应用场景，对于大多数软件应用场景来说并不现实。通常情况下，不仅是单个对象实例需要进行版本检查，整个被修改过的关联对象图也都需要进行版本检查。作为标准设计范例，Hibernate使用长生命周期 Session的方式，或者脱管对象实例的方式来提供自动版本检查。 <br /><br /><strong>12.3.2.长生命周期session和自动版本化 </strong><br />单个 Session实例和它所关联的所有持久化对象实例都被用于整个应用程序事务。Hibernate在同步的时候进行对象实例的版本检查，如果检测到并发修改则抛出异常。由开发人员来决定是否需要捕获和处理这个异常（通常的抉择是给用户 提供一个合并更改，或者在无脏数据情况下重新进行业务操作的机会）。 <br />在等待用户交互的时候， Session 断开底层的JDBC连接。这种方式 以<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>访问的角度来说是最高效的方式。应用程序不需要关心版本检查或脱管对象实例 的重新关联，在每个<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>事务中，应用程序也不需要载入读取对象实例。 <br /><br /><br /><br /><br /><table style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-BOTTOM-WIDTH: 1px; BORDER-RIGHT-WIDTH: 1px" bordercolor="#e0e0e0" cellspacing="1" cellpadding="4" width="95%" align="center" border="1" table-layout="" fixed=""><tbody><tr><td style="HEIGHT: 25px" valign="top" bgcolor="#f6f6f6"><font style="COLOR: rgb(176,176,176)">代码内容</font><br />// foo is an instance loaded earlier by the Session <br />session.reconnect(); // Obtain a new JDBC connection <br />Transaction t = session.beginTransaction(); <br />foo.setProperty("bar"); <br />t.commit(); // End database transaction, flushing the change and checking the version <br />session.disconnect(); // Return JDBC connection </td></tr></tbody></table><br />foo 对象始终和载入它的Session相关联。 Session.reconnect()获取一个新的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>连接（或者 你可以提供一个），并且继续当前的session。Session.disconnect() 方法把session与JDBC连接断开，把<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>连接返回到连接池（除非是你自己提供的数据 库连接）。在Session重新连接上<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>连接之后，你可以对任何可能被其他事务更新过 的对象调用Session.lock()，设置LockMode.READ 锁定模式，这样你就可以对那些你不准备更新的数据进行强制版本检查。此外，你并不需要 锁定那些你准备更新的数据。 <br />假若对disconnect()和reconnect()的显式调用发生得太频繁了，你可以使用hibernate.connection.release_mode来代替。 <br />如果在用户思考的过程中，Session因为太大了而不能保存，那么这种模式是有 问题的。举例来说，一个HttpSession应该尽可能的小。由于 Session是一级缓存，并且保持了所有被载入过的对象，因此我们只应该在那些少量的request/response情况下使用这种策略。而且在这种情况下， Session 里面很快就会有脏数据出现，因此请牢牢记住这一建议。 <br />此外，也请注意，你应该让与<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>连接断开的Session对持久层保持 关闭状态。换句话说，使用有状态的EJB session bean来持有Session， 而不要把它传递到web层（甚至把它序列化到一个单独的层），保存在HttpSession中。 <br /><br /><strong>12.3.3.脱管对象(deatched object)和自动版本化 </strong><br />这种方式下，与持久化存储的每次交互都发生在一个新的Session中。 然而，同一持久化对象实例可以在多次与<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>的交互中重用。应用程序操纵脱管对象实例 的状态，这个脱管对象实例最初是在另一个Session 中载入的，然后 调用 Session.update()，Session.saveOrUpdate(), 或者 Session.merge() 来重新关联该对象实例。 <br /><br /><br /><br /><br /><table style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-BOTTOM-WIDTH: 1px; BORDER-RIGHT-WIDTH: 1px" bordercolor="#e0e0e0" cellspacing="1" cellpadding="4" width="95%" align="center" border="1" table-layout="" fixed=""><tbody><tr><td style="HEIGHT: 25px" valign="top" bgcolor="#f6f6f6"><font style="COLOR: rgb(176,176,176)">代码内容</font><br />// foo is an instance loaded by a previous Session <br />foo.setProperty("bar"); <br />session = factory.openSession(); <br />Transaction t = session.beginTransaction(); <br />session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already <br />t.commit(); <br />session.close(); </td></tr></tbody></table><br />Hibernate会再一次在同步的时候检查对象实例的版本，如果发生更新冲突，就抛出异常。 <br />如果你确信对象没有被修改过，你也可以调用lock() 来设置 LockMode.READ（绕过所有的缓存，执行版本检查），从而取 代 update()操作。 <br /><br /><strong>12.3.4.定制自动版本化行为</strong><br />对于特定的属性和集合，通过为它们设置映射属性optimistic-lock的值 为false，来禁止Hibernate的版本自动增加。这样的话，如果该属性 脏数据，Hibernate将不再增加版本号。 <br />遗留系统的<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>Schema通常是静态的，不可修改的。或者，其他应用程序也可能访问同一数据 库，根本无法得知如何处理版本号，甚至时间戳。在以上的所有场景中，实现版本化不能依靠 <a href="http://www.gamvan.com/database/" target="_blank">数据库</a>表的某个特定列。在的映射中设置 optimistic-lock="all"可以在没有版本或者时间戳属性映射的情况下实现版本检查，此时Hibernate将比较一行记录的每个字段的状态。请注意，只有当Hibernate能够比较新旧状态的情况下，这种方式才能生效，也就是说， 你必须使用单个长生命周期Session模式，而不能使用 session-per-request-with-detached-objects模式。 <br />有些情况下，只要更改不发生交错，并发修改也是允许的。当你在 的映射中设置optimistic-lock="dirty"，Hibernate在同步的时候将只比较有脏 数据的字段。 <br />在以上所有场景中，不管是专门设置一个版本/时间戳列，还是进行全部字段/脏数据字段比较， Hibernate都会针对每个实体对象发送一条UPDATE（带有相应的 WHERE语句）的SQL语句来执行版本检查和数据更新。如果你对关联实体 设置级联关系使用传播性持久化（transitive persistence），那么Hibernate可能会执行不必 要的update语句。这通常不是个问题，但是<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>里面对on update点火 的触发器可能在脱管对象没有任何更改的情况下被触发。因此，你可以在的映射中，通过设置select-before-update="true" 来定制这一行为，强制Hibernate SELECT这个对象实例，从而保证， 在更新记录之前，对象的确是被修改过。 <br /><br /><strong>12.4.悲观锁定(Pessimistic Locking)</strong><br />用户其实并不需要花很多精力去担心锁定策略的问题。通常情况下，只要为JDBC连接指定一下隔 离级别，然后让<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>去搞定一切就够了。然而，高级用户有时候希望进行一个排它的悲观锁定， 或者在一个新的事务启动的时候，重新进行锁定。 <br />Hibernate总是使用<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>的锁定机制，从不在内存中锁定对象！ <br />类LockMode 定义了Hibernate所需的不同的锁定级别。一个锁定 可以通过以下的机制来设置: <br />当Hibernate更新或者插入一行记录的时候，锁定级别自动设置为LockMode.WRITE。 <br />当用户显式的使用<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>支持的SQL格式SELECT ... FOR UPDATE 发送SQL的时候，锁定级别设置为LockMode.UPGRADE <br />当用户显式的使用Oracle<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>的SQL语句SELECT ... FOR UPDATE NOWAIT 的时候，锁定级别设置LockMode.UPGRADE_NOWAIT <br />当Hibernate在“可重复读”或者是“序列化”<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>隔离级别下读取数据的时候，锁定模式 自动设置为LockMode.READ。这种模式也可以通过用户显式指定进行设置。 <br />LockMode.NONE 代表无需锁定。在Transaction结束时， 所有的对象都切换到该模式上来。与session相关联的对象通过调用update() 或者saveOrUpdate()脱离该模式。 <br />"显式的用户指定"可以通过以下几种方式之一来表示: <br />调用 Session.load()的时候指定锁定模式(LockMode)。 <br />调用Session.lock()。 <br />调用Query.setLockMode()。 <br />如果在UPGRADE或者UPGRADE_NOWAIT锁定模式下调用Session.load()，并且要读取的对象尚未被session载入过，那么对象 通过SELECT ... FOR UPDATE这样的SQL语句被载入。如果为一个对象调用 load()方法时，该对象已经在另一个较少限制的锁定模式下被载入了，那么Hibernate就对该对象调用lock() 方法。 <br />如果指定的锁定模式是READ, UPGRADE 或 UPGRADE_NOWAIT，那么Session.lock()就 执行版本号检查。（在UPGRADE 或者UPGRADE_NOWAIT 锁定模式下，执行SELECT ... FOR UPDATE这样的SQL语句。） <br />如果<a href="http://www.gamvan.com/database/" target="_blank">数据库</a>不支持用户设置的锁定模式，Hibernate将使用适当的替代模式（而不是扔出异常）。 这一点可以确保应用程序的可移植性。<img src ="http://www.blogjava.net/lijiajia418/aggbug/65001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lijiajia418/" target="_blank">Binary</a> 2006-08-22 10:50 <a href="http://www.blogjava.net/lijiajia418/archive/2006/08/22/65001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>