﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-学习--共同努力-随笔分类-hibernate</title><link>http://www.blogjava.net/rendong/category/13645.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 01:13:13 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 01:13:13 GMT</pubDate><ttl>60</ttl><item><title>Java 中的悲观锁和乐观锁的实现 (转http://www.blogjava.net/liuwentao253/archive/2006/06/20/53934.html)</title><link>http://www.blogjava.net/rendong/archive/2006/12/27/90326.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Wed, 27 Dec 2006 08:40:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/12/27/90326.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/90326.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/12/27/90326.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/90326.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/90326.html</trackback:ping><description><![CDATA[
		<p>锁（locking） <br />业务逻辑的实现过程中，往往需要保证数据访问的排他性。如在金融系统的日终结算 处理中，我们希望针对某个cut-off时间点的数据进行处理，而不希望在结算进行过程中 （可能是几秒种，也可能是几个小时），数据再发生变化。此时，我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改，这样的机制，在这里，也就是所谓 的“锁”，即<font color="#0000ff"><strong>给我们选定的目标数据上锁，使其无法被其他程序修改</strong></font>。 Hibernate支持两种锁机制：即通常所说的“悲观锁（Pessimistic Locking）” 和“乐观锁（Optimistic Locking）”。</p>
		<p>
				<br />一 ：<font color="#0000ff"><strong>悲观锁</strong></font>（<u>Pessimistic</u> Locking） <br />悲观锁，正如其名，它指的是对数据被外界（包括本系统当前的其他事务，以及来自外部系统的事务处理）修改持保守态度，因此，在整个数据处理过程中，将数据处于锁定 状态。悲观锁的实现，往往依靠数据库提供的锁机制（<font color="#ff0000"><strong><u>也只有数据库层提供的锁机制才能 真正保证数据访问的排他性</u></strong></font>，否则，即使在本系统中实现了加锁机制，也无法保证外部系 统不会修改数据）。 一个典型的倚赖数据库的悲观锁调用： <u>select * from account where name=”Erica” for update 这条sql 语句锁定了account 表中所有符合检索条件（name=”Erica”）的记录。 本次事务提交之前（事务提交时会释放事务过程中的锁），外界无法修改这些记录</u>。 Hibernate的悲观锁，也是基于数据库的锁机制实现。 下面的代码实现了对查询记录的加锁：</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">String hqlStr </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">from TUser as user where user.name=’Erica’</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">; <br /></span>
				<span style="COLOR: #008080">2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Query query </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session.createQuery(hqlStr); <br /></span>
				<span style="COLOR: #008080">3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />query.setLockMode(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">user</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">,LockMode.UPGRADE); </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">加锁 </span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #008080">4</span>
				<span style="COLOR: #008000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">List userList </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> query.list();</span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">执行查询，</span>
		</div>
		<p>获取数据 <u>query.setLockMode</u> 对查询语句中特定别名所对应的记录进行加锁（我们为 TUser类指定了一个别名“user”），这里也就是对返回的所有user记录进行加锁。 观察运行期Hibernate生成的SQL语句： </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">’Erica’ ) </span>
				<span style="COLOR: #0000ff">for</span>
				<span style="COLOR: #000000"> update</span>
		</div>
		<p> 这里Hibernate通过使用数据库的for update子句实现了<font color="#0000ff"><strong>悲观锁</strong></font>机制。 Hibernate的加锁模式有： <br />? LockMode.NONE ： 无锁机制。 <br />? LockMode.WRITE ：Hibernate在Insert和Update记录的时候会自动 获取。 <br />? LockMode.READ ： Hibernate在读取记录的时候会自动获取。 <br /><br />以上这三种锁机制一般由Hibernate内部使用，如Hibernate为了保证Update 过程中对象不会被外界修改，会在save方法实现中自动为目标对象加上WRITE锁。<br /> <br />? LockMode.UPGRADE ：<font color="#0000ff"><strong>利用数据库的for update子句加锁</strong></font>。 <br />? LockMode. UPGRADE_NOWAIT ：Oracle的特定实现，<font color="#0000ff"><strong>利用Oracle的for update nowait子句实现加锁</strong></font>。 <br /><br />上面这两种锁机制是我们在应用层较为常用的，加锁一般通过以下方法实现： <br />Criteria.setLockMode <br />Query.setLockMode <br />Session.lock <br />注意，只有在查询开始之前（也就是Hiberate 生成SQL 之前）设定加锁，才会 真正通过数据库的锁机制进行加锁处理，否则，数据已经通过不包含for update 子句的Select SQL加载进来，所谓数据库加锁也就无从谈起。 </p>
		<p>
				<br />二 ：乐观锁（Optimistic Locking） <br />相对悲观锁而言，乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依 靠数据库的锁机制实现，以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销，特别是对长事务而言，这样的开销往往无法承受。 如一个金融系统，当某个操作员读取用户的数据，并在读出的用户数据的基础上进 行修改时（如更改用户帐户余额），如果采用悲观锁机制，也就意味着整个操作过 程中（从操作员读出数据、开始修改直至提交修改结果的全过程，甚至还包括操作 员中途去煮咖啡的时间），数据库记录始终处于加锁状态，可以想见，如果面对几 百上千个并发，这样的情况将导致怎样的后果。 乐观锁机制在一定程度上解决了这个问题。<font color="#ff0000"><strong>乐观锁 大多是基于数据版本 （Version）记录机制实现</strong></font>。何谓数据版本？即为数据增加一个版本标识，在基于 数据库表的版本解决方案中，一般是通过为数据库表增加一个“version”字段来 实现。 读取出数据时，将此版本号一同读出，之后更新时，对此版本号加一。此时，将提 交数据的版本数据与数据库表对应记录的当前版本信息进行比对，如果提交的数据 版本号大于数据库表当前版本号，则予以更新，否则认为是过期数据。 对于上面修改用户帐户信息的例子而言，假设 ：<br /><br />数据库中帐户信息表中有一个 version字段，当前值为1；而当前帐户余额字段（balance）为$100。 <br />1 ：操作员A 此时将其读出（version=1），并从其帐户余额中扣除$50 （$100-$50）。 <br />2 ： 在操作员A操作的过程中，操作员B也读入此用户信息（version=1），并 从其帐户余额中扣除$20（$100-$20）。 <br />3： 操作员A完成了修改工作，将数据版本号加一（version=2），连同帐户扣 除后余额（balance=$50），提交至数据库更新，此时由于提交数据版本大 于数据库记录当前版本，数据被更新，数据库记录version更新为2。 <br />4： 操作员B完成了操作，也将版本号加一（version=2）试图向数据库提交数 据（balance=$80），但此时比对数据库记录版本时发现，操作员B提交的 数据版本号为2，数据库记录当前版本也为2，不满足“提交版本必须大于记 录当前版本才能执行更新“的乐观锁策略，因此，操作员B 的提交被驳回。 这样，就避免了操作员B 用基于version=1 的旧数据修改的结果覆盖操作 员A的操作结果的可能。 <br /><br />从上面的例子可以看出，乐观锁机制避免了长事务中的数据库加锁开销（操作员A 和操作员B操作过程中，都没有对数据库数据加锁），大大提升了大并发量下的系 统整体性能表现。 需要注意的是，乐观锁机制往往基于系统中的数据存储逻辑，因此也具备一定的局 限性，如在上例中，由于乐观锁机制是在我们的系统中实现，来自外部系统的用户 余额更新操作不受我们系统的控制，因此可能会造成脏数据被更新到数据库中。在 系统设计阶段，我们应该充分考虑到这些情况出现的可能性，并进行相应调整（如 将乐观锁策略在数据库存储过程中实现，对外只开放基于此存储过程的数据更新途 径，而不是将数据库表直接对外公开）。 <font color="#0000ff"><strong>Hibernate 在其数据访问引擎中内置了乐观锁实现</strong></font>。如果不用考虑外部系统对数 据库的更新操作，利用Hibernate提供的透明化乐观锁实现，将大大提升我们的 生产力。 Hibernate中可以通过class描述符的optimistic-lock属性结合version 描述符指定。 <br />现在，我们为之前示例中的TUser加上乐观锁机制。<br /> <br />1． 首先为TUser的class描述符添加optimistic-lock属性：</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">hibernate</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">mapping</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />name</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">org.hibernate.sample.TUser</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />table</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">t_user</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />dynamic</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">update</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">true</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />dynamic</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">insert</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">true</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />optimistic</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">lock</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">version</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />…… <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #000000">&lt;/</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #000000">&lt;/</span>
				<span style="COLOR: #000000">hibernate</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">mapping</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> </span>
		</div>
		<p>optimistic-lock属性有如下可选取值： <br />? none 无乐观锁 <br />? version 通过版本机制实现乐观锁 <br />? dirty 通过检查发生变动过的属性实现乐观锁 <br />? all 通过检查所有属性实现乐观锁 <br /><br />其中<font color="#0000ff"><strong>通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现</strong></font>，同时也 是Hibernate中，<u>目前唯一在数据对象脱离Session发生修改的情况下依然有效的锁机 制</u>。因此，一般情况下，我们都选择version方式作为Hibernate乐观锁实现机制。 <br /><br />2． 添加一个Version属性描述符 <br />代码内容<br /></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">hibernate</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">mapping</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />name</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">org.hibernate.sample.TUser</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />table</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">t_user</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />dynamic</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">update</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">true</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />dynamic</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">insert</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">true</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />optimistic</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">lock</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">version</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080"> 9</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">id  <br /></span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />name</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">id</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />column</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">id</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />type</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">java.lang.Integer</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">generator </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">native</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">15</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;/</span>
				<span style="COLOR: #000000">generator</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">16</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;/</span>
				<span style="COLOR: #000000">id</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">17</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">version  <br /></span>
				<span style="COLOR: #008080">18</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />column</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">version</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">19</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />name</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">version</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">20</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />type</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">java.lang.Integer</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">21</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">/&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">22</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />……  <br /></span>
				<span style="COLOR: #008080">23</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;/</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">24</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">&lt;/</span>
				<span style="COLOR: #000000">hibernate</span>
				<span style="COLOR: #000000">-</span>
				<span style="COLOR: #000000">mapping</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">  <br /></span>
				<span style="COLOR: #008080">25</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
		<p>注意version 节点必须出现在ID 节点之后。 这里我们声明了一个version属性，用于存放用户的版本信息，保存在TUser表的 version字段中。 此时如果我们尝试编写一段代码，更新TUser表中记录数据，如： <br />代码内容</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">Criteria criteria </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session.createCriteria(TUser.</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080">2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />criteria.add(Expression.eq(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">name</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">,</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">Erica</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">));  <br /></span>
				<span style="COLOR: #008080">3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />List userList </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> criteria.list();  <br /></span>
				<span style="COLOR: #008080">4</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />TUser user </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">(TUser)userList.get(</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080">5</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Transaction tx </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session.beginTransaction();  <br /></span>
				<span style="COLOR: #008080">6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />user.setUserType(</span>
				<span style="COLOR: #000000">1</span>
				<span style="COLOR: #000000">); </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">更新UserType字段  </span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #008080">7</span>
				<span style="COLOR: #008000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">tx.commit();  <br /></span>
				<span style="COLOR: #008080">8</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
		<p>每次对TUser进行更新的时候，我们可以发现，数据库中的version都在递增。 而如果我们尝试在tx.commit 之前，启动另外一个Session，对名为Erica 的用 户进行操作，以模拟并发更新时的情形： <br />代码内容</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">Session session</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> getSession();  <br /></span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Criteria criteria </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session.createCriteria(TUser.</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />criteria.add(Expression.eq(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">name</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">,</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">Erica</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">));  <br /></span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Session session2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> getSession();  <br /></span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Criteria criteria2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session2.createCriteria(TUser.</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />criteria2.add(Expression.eq(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">name</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">,</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">Erica</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">));  <br /></span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />List userList </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> criteria.list();  <br /></span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />List userList2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> criteria2.list();TUser user </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">(TUser)userList.get(</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080"> 9</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />TUser user2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000">(TUser)userList2.get(</span>
				<span style="COLOR: #000000">0</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Transaction tx </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session.beginTransaction();  <br /></span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />Transaction tx2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> session2.beginTransaction();  <br /></span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />user2.setUserType(</span>
				<span style="COLOR: #000000">99</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />tx2.commit();  <br /></span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />user.setUserType(</span>
				<span style="COLOR: #000000">1</span>
				<span style="COLOR: #000000">);  <br /></span>
				<span style="COLOR: #008080">15</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />tx.commit();  <br /></span>
				<span style="COLOR: #008080">16</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
		<p>执行以上代码，代码将在tx.commit()处抛出<font color="#0000ff"><strong>StaleObjectStateException</strong></font>异 常，并指出版本检查失败，当前事务正在试图提交一个过期数据。通过捕捉这个异常，我 们就可以在乐观锁校验失败时进行相应处理。 <br /></p>
<img src ="http://www.blogjava.net/rendong/aggbug/90326.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-12-27 16:40 <a href="http://www.blogjava.net/rendong/archive/2006/12/27/90326.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c3p0</title><link>http://www.blogjava.net/rendong/archive/2006/12/02/85058.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Sat, 02 Dec 2006 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/12/02/85058.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/85058.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/12/02/85058.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/85058.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/85058.html</trackback:ping><description><![CDATA[&lt;hibernate-configuration&gt; <br />&lt;session-factory&gt; 
<p>&lt;property name="dialect"&gt;org.hibernate.dialect.Oracle9Dialect&lt;/property&gt; <br />&lt;property name="show_sql"&gt;true&lt;/property&gt; <br />&lt;property name="current_session_context_class"&gt;thread&lt;/property&gt; <br />&lt;!--Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数--&gt; <br />&lt;property name="jdbc.fetch_size"&gt;20&lt;/property&gt; <br />&lt;!--Batch Size是设定对数据库进行批量删除，批量更新和批量插入的时候的批次大小，有点相当于设置Buffer缓冲区大小的意思--&gt; <br />&lt;property name="jdbc.batch_size "&gt;20&lt;/property&gt; <br />&lt;property name="connection.username"&gt;HNMC&lt;/property&gt; <br />&lt;property name="connection.password"&gt;sundy&lt;/property&gt; <br />&lt;property name="connection.url"&gt;jdbc:oracle:thin:@192.168.0.20:1521:ora9&lt;/property&gt; <br />&lt;property name="connection.driver_class"&gt;oracle.jdbc.driver.OracleDriver&lt;/property&gt;</p><p>&lt;!--  在这种情况下，没问题啊 --&gt;<br />&lt;property name="c3p0.timeout"&gt;60&lt;/property&gt; <br />&lt;property name="c3p0.idle_test_period"&gt;600&lt;/property&gt;<br /><br /><br />&lt;!--     <br /></p><p>&lt;!--&lt;property name="c3p0.idle_test_period"&gt;120&lt;/property&gt;--&gt; <br />如改以下俩值，或他们差距很大：</p><p>&lt;property name="c3p0.timeout"&gt;600&lt;/property&gt;</p><p>&lt;!--&lt;property name="c3p0.idle_test_period"&gt;60&lt;/property&gt;--&gt;</p><p>当我启动tomcat，运行程序后，空闲600后出现下列异常,但程序还照常运行<br /><br />--&gt;<br /><br />&lt;!--  </p><p>Hibernate里可以设置的属性不多： <br />#c3p0-native property name hibernate configuration key <br />#c3p0.acquireIncrement hibernate.c3p0.acquire_increment <br />#c3p0.idleConnectionTestPeriod hibernate.c3p0.idle_test_period <br />#c3p0.initialPoolSize not available -- uses minimum size <br />#c3p0.maxIdleTime hibernate.c3p0.timeout <br />#c3p0.maxPoolSize hibernate.c3p0.max_size <br />#c3p0.maxStatements hibernate.c3p0.max_statements <br />#c3p0.minPoolSize hibernate.c3p0.min_size <br />#c3p0.testConnectionsOnCheckout hibernate.c3p0.validate hibernate 2.x only!</p><p>另外的属性你需要配置c3p0.properties <br />比如： <br />c3p0.acquireRetryDelay=111 <br />c3p0.acquireRetryAttempts=22 <br />c3p0.breakAfterAcquireFailure=true<br /><br />--&gt;<br /><br /><br /><br />&lt;property name="hibernate.connection.provider_class"&gt;org.hibernate.connection.C3P0ConnectionProvider&lt;/property&gt; <br />&lt;property name="hibernate.c3p0.max_size"&gt;2&lt;/property&gt; <br />&lt;property name="hibernate.c3p0.min_size"&gt;2&lt;/property&gt; <br />&lt;property name="hibernate.c3p0.timeout"&gt;50000&lt;/property&gt; <br />&lt;property name="hibernate.c3p0.max_statements"&gt;100&lt;/property&gt; <br />&lt;property name="hibernate.c3p0.idle_test_period"&gt;3000&lt;/property&gt; <br />&lt;property name="hibernate.c3p0.acquire_increment"&gt;2&lt;/property&gt; <br /><br />&lt;!-- 另&lt;property name="hibernate.c3p0.validate"&gt;false&lt;/property&gt;确实在hibernate中不可设置  --&gt;<br />&lt;property name="hibernate.c3p0.validate"&gt;false&lt;/property&gt;<br /><br /><br />&lt;!--C3P0 setting--&gt;</p><p>&lt;property name="c3p0.max_size"&gt;20&lt;/property&gt; <br />&lt;property name="c3p0.min_size"&gt;5&lt;/property&gt; <br />&lt;!--获取连接的等待时间--&gt; <br />&lt;property name="c3p0.timeout"&gt;3600&lt;/property&gt; <br />&lt;property name="c3p0.max_statements"&gt;100&lt;/property&gt; <br />&lt;!--每隔3600毫秒测试连接是否可以正常使用--&gt; <br />&lt;property name="c3p0.idle_test_period"&gt;3600&lt;/property&gt; <br />&lt;property name="c3p0.acquire_increment"&gt;2&lt;/property&gt;</p><p>&lt;mapping resource="com/sundy/hnmc/beans/AccountBean.hbm.xml"/&gt; <br />&lt;/session-factory&gt; <br />&lt;/hibernate-configuration&gt; <br /><br /><br /><br />另一个设置<br /> <span style="COLOR: #008000">&lt;!--</span><span style="COLOR: #008000"> 数据源配置 </span><span style="COLOR: #008000">--&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean </span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="dataSource"</span><span style="COLOR: #ff0000"> class</span><span style="COLOR: #0000ff">="com.mchange.v2.c3p0.ComboPooledDataSource"</span><span style="COLOR: #ff0000"> destroy-method</span><span style="COLOR: #0000ff">="close"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="driverClass"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">org.gjt.mm.mysql.Driver</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="jdbcUrl"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">jdbc:mysql://localhost/tycho?useUnicode=true</span><span style="COLOR: #ff0000">&amp;amp;</span><span style="COLOR: #000000">characterEncoding=utf-8</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property </span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="properties"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">props</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="hibernate.hbm2ddl.auto"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">update</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="c3p0.minPoolSize"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">1</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="hc3p0.maxPoolSize"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">10</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="hc3p0.timeout"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">60</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="c3p0.max_statement"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">50</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="c3p0.testConnectionOnCheckout"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">true</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="hibernate.c3p0.testConnectionOnCheckout"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">false</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="user"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">root</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            </span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">prop </span><span style="COLOR: #ff0000">key</span><span style="COLOR: #0000ff">="password"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">root</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">prop</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">props</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />      </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    </span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;<br /><br /><br /><br /><font color="#000000">&lt;property name="hibernate.connection.provider_class"&gt;org.hibernate.connection.C3P0ConnectionProvider&lt;/property&gt;<br />&lt;property name="hibernate.c3p0.max_size"&gt;20&lt;/property&gt;<br />&lt;property name="hibernate.c3p0.min_size"&gt;5&lt;/property&gt;<br />&lt;property name="hibernate.c3p0.timeout"&gt;120&lt;/property&gt;<br />&lt;property name="hibernate.c3p0.max_statements"&gt;100&lt;/property&gt;<br />&lt;property name="hibernate.c3p0.idle_test_period"&gt;120&lt;/property&gt;<br />&lt;property name="hibernate.c3p0.acquire_increment"&gt;2&lt;/property&gt; </font><br /><br /></span></p><p><span style="COLOR: #0000ff"></span> </p><p><span style="COLOR: #0000ff"></span> </p><p><span style="COLOR: #0000ff"></span> </p><p><span style="COLOR: #0000ff"> </span></p><img src ="http://www.blogjava.net/rendong/aggbug/85058.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-12-02 17:32 <a href="http://www.blogjava.net/rendong/archive/2006/12/02/85058.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>好的网址</title><link>http://www.blogjava.net/rendong/archive/2006/09/03/67343.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Sat, 02 Sep 2006 16:44:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/09/03/67343.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/67343.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/09/03/67343.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/67343.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/67343.html</trackback:ping><description><![CDATA[
		<a href="http://blog.csdn.net/baggio785/">http://blog.csdn.net/baggio785/</a>
		<br />
		<br />
		<a href="http://tag.csdn.net/tag/hibernate/1.html">http://tag.csdn.net/tag/hibernate/1.html</a>
<img src ="http://www.blogjava.net/rendong/aggbug/67343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-09-03 00:44 <a href="http://www.blogjava.net/rendong/archive/2006/09/03/67343.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>1.1 Hibernate API 变化 </title><link>http://www.blogjava.net/rendong/archive/2006/09/03/67341.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Sat, 02 Sep 2006 16:41:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/09/03/67341.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/67341.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/09/03/67341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/67341.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/67341.html</trackback:ping><description><![CDATA[CSDN 推荐tag:<a href="http://tag.csdn.net/tag/api/1.html" target="_blank">api</a> <a href="http://tag.csdn.net/tag/com/1.html" target="_blank">com</a> <a href="http://tag.csdn.net/tag/hibernate/1.html" target="_blank">hibernate</a> <a href="http://tag.csdn.net/tag/ice/1.html" target="_blank">ice</a> <a href="http://tag.csdn.net/tag/java/1.html" target="_blank">java</a> <a href="http://tag.csdn.net/tag/os/1.html" target="_blank">os</a> <a href="http://tag.csdn.net/tag/sql/1.html" target="_blank">sql</a> <a href="http://tag.csdn.net/tag/函数/1.html" target="_blank">函数</a> <a href="http://tag.csdn.net/tag/软件/1.html" target="_blank">软件</a>  
<div style="CLEAR: both"></div><script><![CDATA[unction StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}]]&gt;</script><div class="post" id="article"><div class="postTitle"><a href="http://blog.csdn.net/baggio785/archive/2006/03/13/623674.aspx"><img height="13" src="http://blog.csdn.net/images/zhuan.gif" width="15" border="0" /><font color="#ffffff"> 如何从Hibernate2.1升级到Hibernate3.0？</font></a></div><div class="postText">选自《精通Hibernate：Java对象持久化技术详解》 作者：孙卫琴 来源: www.javathinker.org <br />如果转载，请标明出处，谢谢 <br /><br />1.1 Hibernate API 变化 <br />1.1.1 包名 <br />1.1.2 org.hibernate.classic包 <br />1.1.3 Hibernate所依赖的第三方软件包 <br />1.1.4 异常模型 <br />1.1.5 Session接口 <br />1.1.6 createSQLQuery() <br />1.1.7 Lifecycle 和 Validatable 接口 <br />1.1.8 Interceptor接口 <br />1.1.9 UserType和CompositeUserType接口 <br />1.1.10 FetchMode类 <br />1.1.11 PersistentEnum类 <br />1.1.12 对Blob 和Clob的支持 <br />1.1.13 Hibernate中供扩展的API的变化 <br />1.2 元数据的变化 <br />1.2.1 检索策略 <br />1.2.2 对象标识符的映射 <br />1.2.3 集合映射 <br />1.2.4 DTD <br />1.3 查询语句的变化 <br />1.3.1 indices()和elements()函数 <br /><br /><br />尽管Hibernate 3.0 与Hibernate2.1的源代码是不兼容的，但是当Hibernate开发小组在设计Hibernate3.0时，为简化升级Hibernate版本作了周到的考虑。对于现有的基于Hibernate2.1的Java项目，可以很方便的把它升级到Hibernate3.0。 <br /><br />本文描述了Hibernate3.0版本的新变化，Hibernate3.0版本的变化包括三个方面： <br />（1）API的变化，它将影响到Java程序代码。 <br />（2）元数据，它将影响到对象-关系映射文件。 <br />（3）HQL查询语句。 <br /><br />值得注意的是， Hibernate3.0并不会完全取代Hibernate2.1。在同一个应用程序中，允许Hibernate3.0和Hibernate2.1并存。 <br /><br />1.1 Hibernate API 变化 <br /><br />1.1.1 包名 <br /><br />Hibernate3.0的包的根路径为: “org.hibernate” ，而在Hibernate2.1中为“net.sf.hibernate”。这一命名变化使得Hibernate2.1和Hibernate3.0能够同时在同一个应用程序中运行。 <br /><br />如果希望把已有的应用升级到Hibernate3.0，那么升级的第一步是把Java源程序中的所有“net.sf.hibernate”替换为“org.hibernate”。 <br /><br />Hibernate2.1中的“net.sf.hibernate.expression”包被改名为“org.hibernate.criterion”。假如应用程序使用了Criteria API，那么在升级的过程中，必须把Java源程序中的所有“net.sf.hibernate.expression”替换为“org.hibernate.criterion”。 <br /><br />如果应用使用了除Hibernate以外的其他外部软件，而这个外部软件又引用了Hibernate的接口，那么在升级时必须十分小心。例如EHCache拥有自己的CacheProvider： net.sf.ehcache.hibernate.Provider，在这个类中引用了Hibernate2.1中的接口，在升级应用时，可以采用以下办法之一来升级EHCache: <br /><br />（1）手工修改net.sf.ehcache.hibernate.Provider类，使它引用Hibernate3.0中的接口。 <br />（2）等到EHCache软件本身升级为使用Hibernate3.0后，使用新的EHCache软件。 <br />（3）使用Hibernate3.0中内置的CacheProvider：org.hibernate.cache.EhCacheProvider。 <br /><br />1.1.2 org.hibernate.classic包 <br /><br />Hibernate3.0把一些被废弃的接口都转移到org.hibernate.classic中。 <br /><br />1.1.3 Hibernate所依赖的第三方软件包 <br /><br />在Hibernate3.0的软件包的lib目录下的README.txt文件中，描述了Hibernate3.0所依赖的第三方软件包的变化。 <br /><br />1.1.4 异常模型 <br /><br />在Hibernate3.0中，HibernateException异常以及它的所有子类都继承了java.lang.RuntimeException。因此在编译时，编译器不会再检查HibernateException。 <br /><br />1.1.5 Session接口 <br /><br />在Hibernate3.0中，原来Hibernate2.1的Session接口中的有些基本方法也被废弃，但为了简化升级，这些方法依然是可用的，可以通过org.hibernate.classic.Session子接口来访问它们，例如： <br />org.hibernate.classic.Session session=sessionFactory.openSession(); <br />session.delete("delete from Customer "); <br />在Hibernate3.0中，org.hibernate.classic.Session接口继承了org.hibernate.Session接口，在org.hibernate.classic.Session接口中包含了一系列被废弃的方法，如find()、interate()等。SessionFactory接口的openSession()方法返回org.hibernate.classic.Session类型的实例。如果希望在程序中完全使用Hibernate3.0，可以采用以下方式创建Session实例： <br /><br />org.hibernate.Session session=sessionFactory.openSession(); <br /><br />如果是对已有的程序进行简单的升级，并且希望仍然调用Hibernate2.1中Session的一些接口，可以采用以下方式创建Session实例： <br /><br />org.hibernate.classic.Session session=sessionFactory.openSession(); <br /><br />在Hibernate3.0中，Session接口中被废弃的方法包括： <br />* 执行查询的方法：find()、iterate()、filter()和delete(String hqlSelectQuery) <br />* saveOrUpdateCopy() <br /><br />Hibernate3.0一律采用createQuery()方法来执行所有的查询语句，采用DELETE 查询语句来执行批量删除，采用merge()方法来替代 saveOrUpdateCopy()方法。 <br /><br />提示：在Hibernate2.1中，Session的delete()方法有几种重载形式，其中参数为HQL查询语句的delete()方法在Hibernate3.0中被废弃，而参数为Ojbect类型的的delete()方法依然被支持。delete(Object o)方法用于删除参数指定的对象，该方法支持级联删除。 <br />Hibernate2.1没有对批量更新和批量删除提供很好的支持，参见&lt;&lt;精通Hibernate&gt;&gt;一书的第13章的13.1.1节（批量更新和批量删除），而Hibernate3.0对批量更新和批量删除提供了支持，能够直接执行批量更新或批量删除语句，无需把被更新或删除的对象先加载到内存中。以下是通过Hibernate3.0执行批量更新的程序代码： <br />Session session = sessionFactory.openSession(); <br />Transaction tx = session.beginTransaction(); <br />String hqlUpdate = "update Customer set name = :newName where name = :oldName"; <br />int updatedEntities = s.createQuery( hqlUpdate ) <br />.setString( "newName", newName ) <br />.setString( "oldName", oldName ) <br />.executeUpdate(); <br />tx.commit(); <br />session.close(); <br />以下是通过Hibernate3.0执行批量删除的程序代码： <br />Session session = sessionFactory.openSession(); <br />Transaction tx = session.beginTransaction(); <br />String hqlDelete = "delete Customer where name = :oldName"; <br />int deletedEntities = s.createQuery( hqlDelete ) <br />.setString( "oldName", oldName ) <br />.executeUpdate(); <br />tx.commit(); <br />session.close(); <br /><br />1.1.6 createSQLQuery() <br /><br />在Hibernate3.0中，Session接口的createSQLQuery()方法被废弃，被移到org.hibernate.classic.Session接口中。Hibernate3.0采用新的SQLQuery接口来完成相同的功能。 <br /><br />1.1.7 Lifecycle 和 Validatable 接口 <br /><br />Lifecycle和Validatable 接口被废弃，并且被移到org.hibernate.classic包中。 <br /><br />1.1.8 Interceptor接口 <br /><br />在Interceptor 接口中加入了两个新的方法。 用户创建的Interceptor实现类在升级的过程中，需要为这两个新方法提供方法体为空的实现。此外，instantiate()方法的参数作了修改，isUnsaved()方法被改名为isTransient()。 <br /><br />1.1.9 UserType和CompositeUserType接口 <br /><br />在UserType和CompositeUserType接口中都加入了一些新的方法，这两个接口被移到org.hibernate.usertype包中，用户定义的UserType和CompositeUserType实现类必须实现这些新方法。 <br />Hibernate3.0提供了ParameterizedType接口，用于更好的重用用户自定义的类型。 <br />1.1.10 FetchMode类 <br /><br />FetchMode.LAZY 和 FetchMode.EAGER被废弃。取而代之的分别为FetchMode.SELECT 和FetchMode.JOIN。 <br /><br />1.1.11 PersistentEnum类 <br /><br />PersistentEnum被废弃并删除。已经存在的应用应该采用UserType来处理枚举类型。 <br /><br />1.1.12 对Blob 和Clob的支持 <br /><br />Hibernate对Blob和Clob实例进行了包装，使得那些拥有Blob或Clob类型的属性的类的实例可以被游离、序列化或反序列化，以及传递到merge()方法中。 <br /><br />1.1.13 Hibernate中供扩展的API的变化 <br /><br />org.hibernate.criterion、 org.hibernate.mapping、 org.hibernate.persister和org.hibernate.collection 包的结构和实现发生了重大的变化。多数基于Hibernate <br />2.1 的应用不依赖于这些包，因此不会被影响。如果你的应用扩展了这些包中的类，那么必须非常小心的对受影响的程序代码进行升级。 <br /><br />1.2 元数据的变化 <br /><br />1.2.1 检索策略 <br /><br />在Hibernate2.1中，lazy属性的默认值为“false”，而在Hibernate3.0中，lazy属性的默认值为“true”。在升级映射文件时，如果原来的映射文件中的有关元素，如、等没有显式设置lazy属性，那么必须把它们都显式的设置为lazy=“true”。如果觉得这种升级方式很麻烦，可以采取另一简单的升级方式：在元素中设置: default-lazy=“false”。 <br /><br />1.2.2 对象标识符的映射 <br /><br />unsaved-value属性是可选的，在多数情况下，Hibernate3.0将把unsaved-value="0" 作为默认值。 <br /><br />在Hibernate3.0中，当使用自然主键和游离对象时，不再强迫实现Interceptor.isUnsaved()方法。 如果没有设置这个方法，当Hibernate3.0无法区分对象的状态时，会查询数据库，来判断这个对象到底是临时对象，还是游离对象。不过，显式的使用Interceptor.isUnsaved()方法会获得更好的性能，因为这可以减少Hibernate直接访问数据库的次数。 <br /><br />1.2.3 集合映射 <br /><br />元素在某些情况下被和元素替代。此外，Hibernate3.0用 元素来替代原来的.元素，用元素来替代原来的元素。 <br /><br />1.2.4 DTD <br /><br />对象-关系映射文件中的DTD文档，由原来的： <br /><a href="http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><font color="#ff0000">http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd</font></a> <br />改为： <br /><a href="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><font color="#ff0000">http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd</font></a> <br /><br />1.3 查询语句的变化 <br /><br />Hibernate3.0 采用新的基于ANTLR的HQL/SQL查询翻译器，不过，Hibernate2.1的查询翻译器也依然存在。在Hibernate的配置文件中，hibernate.query.factory_class属性用来选择查询翻译器。例如： <br />（1）选择Hibernate3.0的查询翻译器： <br />hibernate.query.factory_class= org.hibernate.hql.ast.ASTQueryTranslatorFactory <br />（2）选择Hibernate2.1的查询翻译器 <br />hibernate.query.factory_class= org.hibernate.hql.classic.ClassicQueryTranslatorFactory <br /><br />提示：ANTLR是用纯Java语言编写出来的一个编译工具，它可生成Java语言或者是C++的词法和语法分析器，并可产生语法分析树并对该树进行遍历。ANTLR由于是纯Java的，因此可以安装在任意平台上，但是需要JDK的支持。 <br />Hibernate开发小组尽力保证Hibernate3.0的查询翻译器能够支持Hibernate2.1的所有查询语句。不过，对于许多已经存在的应用，在升级过程中，也不妨仍然使用Hibernate2.1的查询翻译器。 <br />值得注意的是， Hibernate3.0的查询翻译器存在一个Bug：不支持某些theta-style连结查询方言：如Oracle8i的OracleDialect方言、Sybase11Dialect。解决这一问题的办法有两种：（1）改为使用支持ANSI-style连结查询的方言，如 Oracle9Dialect,（2）如果升级的时候遇到这一问题，那么还是改为使用Hibernate2.1的查询翻译器。 <br /><br />1.3.1 indices()和elements()函数 <br /><br />在HQL的select子句中废弃了indices()和elements()函数，因为这两个函数的语法很让用户费解，可以用显式的连接查询语句来替代 select elements(...) 。而在HQL的where子句中，仍然可以使用elements()函数。<br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=623674</p></div></div><img src ="http://www.blogjava.net/rendong/aggbug/67341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-09-03 00:41 <a href="http://www.blogjava.net/rendong/archive/2006/09/03/67341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大大洒洒</title><link>http://www.blogjava.net/rendong/archive/2006/09/03/67339.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Sat, 02 Sep 2006 16:37:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/09/03/67339.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/67339.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/09/03/67339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/67339.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/67339.html</trackback:ping><description><![CDATA[
		<div id="LastMDatecns!8BC51E4BE025FAC0!295">2006/5/16</div>
		<h4 class="TextColor1" id="subjcns!8BC51E4BE025FAC0!295" style="MARGIN-BOTTOM: 0px">hibernate中session.delete(sql),3.1与2.0的区别,导致的错误</h4>
		<div id="msgcns!8BC51E4BE025FAC0!295">
				<div>今天使用session.delete(sql);报下面的错误:</div>
				<div> </div>
				<div>org.hibernate.MappingException: Unknown entity: java.lang.String<br /> at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:569)<br /> at org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1086)<br /> at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:63)<br /> at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:579)</div>
				<div> </div>
				<div>查查终于知道原因:</div>
				<div> </div>
				<div>    session.delete(sql)是2.0的接口,3.1中已经废弃,同时废弃的有:<br />    find()、iterate()、filter()和delete(String hqlSelectQuery),saveOrUpdateCopy()</div>
				<div> </div>
				<div>  如果要使用的话,可以采用以下方式创建Session实例： <br /><br />      org.hibernate.classic.Session session=sessionFactory.openSession(); </div>
				<div> </div>
				<div>      org.hibernate.classic.Session保留了2.0的接口</div>
				<div> </div>
				<div>下面是3.1的reference里面这样写的,我使用了,但是还是报错,郁闷:</div>
				<div> </div>
				<div>1) Hibernate3.0执行批量删除的程序代码： <br />Session session = sessionFactory.openSession(); <br />Transaction tx = session.beginTransaction(); <br />String hqlDelete = "delete Customer where name = :oldName"; <br />int deletedEntities = s.createQuery( hqlDelete ) <br />.setString( "oldName", oldName ) <br />.executeUpdate(); <br />tx.commit(); <br />session.close();</div>
				<div> </div>
				<div>2)Hibernate3.0执行批量更新的程序代码： <br />Session session = sessionFactory.openSession(); <br />Transaction tx = session.beginTransaction(); <br />String hqlUpdate = "update Customer set name = :newName where name = :oldName"; <br />int updatedEntities = s.createQuery( hqlUpdate ) <br />.setString( "newName", newName ) <br />.setString( "oldName", oldName ) <br />.executeUpdate(); <br />tx.commit(); <br />session.close(); </div>
				<div> </div>
				<div>我按照上面的写法,运行后报错如下:</div>
				<div>
						<br />org.hibernate.QueryException: query must begin with SELECT or FROM: delete [delete Resource r where r.nodeId=:nodeId and r.devId is not null ]<br /> at org.hibernate.hql.classic.ClauseParser.token(ClauseParser.java:83)<br /> at org.hibernate.hql.classic.PreprocessingParser.token(PreprocessingParser.java:108)<br /> at org.hibernate.hql.classic.ParserHelper.parse(ParserHelper.java:28)<br /> at org.hibernate.hql.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:176)<br /> at org.hibernate.hql.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:152)<br /> at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)<br /> at org.hibernate.impl.SessionImpl.getQueries(SessionImpl.java:884)<br /> at org.hibernate.impl.SessionImpl.executeUpdate(SessionImpl.java:865)<br /> at org.hibernate.impl.QueryImpl.executeUpdate(QueryImpl.java:89)</div>
				<div>
						<br />
						<br />
						<h4 class="TextColor1" id="subjcns!8BC51E4BE025FAC0!296" style="MARGIN-BOTTOM: 0px">昨天的问题解决了</h4>
						<div id="msgcns!8BC51E4BE025FAC0!296">
								<div>又把hibernate3的手册仔细的看了一遍,确认自己的写法是没错的,然后又上hibernate的论坛,几乎没有人有我的这个问题,这才想到是不是同事在hibernate.hbm.xml中设置了什么参数,使得我不能使用3.0的特性呢?</div>
								<div>      看了,果真如此,郁闷哦~</div>
								<div>     里面有一句:</div>
								<div>     &lt;property name="hibernate.query.factory_class"&gt;org.hibernate.hql.classic.ClassicQueryTranslatorFactory&lt;/property&gt;</div>
								<div>     这样就使用了2.0的接口.郁闷啊.</div>
								<div>     把这句去掉就OK了.</div>
								<div> </div>
								<div>     附:</div>
								<div>      因为使用了中文拼装的hql后,中文会变成问号,大致如下:</div>
								<div> </div>
								<div>      String hql="from user u where u.name like %"+userName+"%";</div>
								<div> </div>
								<div>      3.0版本是:</div>
								<div>      Query query = session.createQuery("from user u where u.name like :username").setString("username",userName);<br /><br /><br /><br /><br /><table cellspacing="0" cellpadding="0" width="600" border="0"><tbody><tr><td width="600"><table style="TABLE-LAYOUT: fixed" cellpadding="3" width="580"><tbody><tr><td><pre><div class="text" readonly="true">现在要通过一个主键id去数据库中删除对应的一条记录，我该怎样做？如果是将参数delId传递进来的话，那该怎么处理？
  我这样做的，但是报了错
  public void delfun(String delId) throws DatastoreException {
  Session session = HibernateUtil.getSession();
  Transaction tx = null;
  try{
    tx = session.beginTransaction();
             Info info = (Info)session.load(Info.class,id);  //出错行
             session.delete(delId);    
             tx.commit();
  }
  catch(Exception ex) {
    HibernateUtil.rollbackTransaction(tx);
    throw DatastoreException.datastoreError(ex);
  }
  finally {
    HibernateUtil.closeSession(session);
  }
  }
错误信息为：
com.framework.exceptions.DatastoreException.datastoreError(DatastoreException.java:28)
com.service.NpisServiceImpl.delGyinfo(NpisServiceImpl.java:131)

</div></pre></td></tr></tbody></table></td></tr><tr><td width="600" height="10"></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="580" border="0"><tbody><tr class="color1" height="25"><td width="20"></td><td width="360"><font color="#3366cc">回复人：<b>pdvv(我爱花猫) </b></font></td><td width="120"><font color="#000000">2006-3-1 17:32:22</font></td><td width="80"><font color="#000000">得分:</font><font color="#000000">0</font></td></tr><tr><td bgcolor="#0066cc" colspan="4" height="1"></td></tr><tr><td colspan="4" height="5"></td></tr><tr><td><font color="#ffffff">?</font></td><td colspan="3"><table style="TABLE-LAYOUT: fixed" cellpadding="3" width="580"><tbody><tr><td><pre><div class="text" readonly="true">
你给出的异常应该属于你自己框架的信息吧，没有多少参考价值。
使用Session.load()要确保数据一定存在，还是用get()吧；
或者直接session.delete("from INFO where ID = 1");
</div></pre></td></tr></tbody></table></td></tr><tr><td align="right" colspan="4" height="10"><font color="#ff6633"><b><a href="http://www.bczs.net/xml/2006/3/1/4586320.xml#top"><font color="#3366cc">Top</font></a></b></font></td></tr><tr><td colspan="4" height="5"></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="580" border="0"><tbody><tr class="color1" height="25"><td width="20"></td><td width="360"><font color="#3366cc">回复人：<b>yuanjian0211(元剑) </b></font></td><td width="120"><font color="#000000">2006-3-1 17:46:04</font></td><td width="80"><font color="#000000">得分:</font><font color="#000000">0</font></td></tr><tr><td bgcolor="#0066cc" colspan="4" height="1"></td></tr><tr><td colspan="4" height="5"></td></tr><tr><td><font color="#ffffff">?</font></td><td colspan="3"><table style="TABLE-LAYOUT: fixed" cellpadding="3" width="580"><tbody><tr><td><pre><div class="text" readonly="true">
错误提示信息为：
Hibernate: select gyinfo0_.id as id0_, info0_.userid as userid0_, info0_.tit
le as title0_,info0_.descript as descript0_ from Info info0_ where info0_.id=?

请指点
</div></pre></td></tr></tbody></table></td></tr><tr><td align="right" colspan="4" height="10"><font color="#ff6633"><b><a href="http://www.bczs.net/xml/2006/3/1/4586320.xml#top"><font color="#3366cc">Top</font></a></b></font></td></tr><tr><td colspan="4" height="5"></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="580" border="0"><tbody><tr class="color1" height="25"><td width="20"></td><td width="360"><font color="#3366cc">回复人：<b>yuanjian0211(元剑) </b></font></td><td width="120"><font color="#000000">2006-3-1 17:56:29</font></td><td width="80"><font color="#000000">得分:</font><font color="#000000">0</font></td></tr><tr><td bgcolor="#0066cc" colspan="4" height="1"></td></tr><tr><td colspan="4" height="5"></td></tr><tr><td><font color="#ffffff">?</font></td><td colspan="3"><table style="TABLE-LAYOUT: fixed" cellpadding="3" width="580"><tbody><tr><td><pre><div class="text" readonly="true">
id在数据库表中为bigint型
在对象中为long型
</div></pre></td></tr></tbody></table></td></tr><tr><td align="right" colspan="4" height="10"><font color="#ff6633"><b><a href="http://www.bczs.net/xml/2006/3/1/4586320.xml#top"><font color="#3366cc">Top</font></a></b></font></td></tr><tr><td colspan="4" height="5"></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="580" border="0"><tbody><tr class="color1" height="25"><td width="20"></td><td width="360"><font color="#3366cc">回复人：<b>iori_powermax() </b></font></td><td width="120"><font color="#000000">2006-03-02 01:06:00</font></td><td width="80"><font color="#000000">得分:</font><font color="#000000">0</font></td></tr><tr><td bgcolor="#0066cc" colspan="4" height="1"></td></tr><tr><td colspan="4" height="5"></td></tr><tr><td><font color="#ffffff">?</font></td><td colspan="3"><table style="TABLE-LAYOUT: fixed" cellpadding="3" width="580"><tbody><tr><td><pre><div class="text" readonly="true">我也在学习hibernate,不知道说的对不对.
你删除的应该是整个对象,而不是一个id,所以应该为:
Info info = (Info)session.load(Info.class,id); 
session.delete(info);  
或者还有一种删除记录的方法:
info=(Info)sn.creatQuery("from Info as a where a.ID= '"+delId+"'").uniqueResult();
sn.delete(info);

另外想问一下大家:
hibernate的creatSQLQuery()是不是只支持查询?好象增删改都不可以

</div></pre></td></tr></tbody></table></td></tr><tr><td align="right" colspan="4" height="10"><font color="#ff6633"><b><a href="http://www.bczs.net/xml/2006/3/1/4586320.xml#top"><font color="#3366cc">Top</font></a></b></font></td></tr><tr><td colspan="4" height="5"></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="580" border="0"><tbody><tr class="color1" height="25"><td width="20"></td><td width="360"><font color="#3366cc">回复人：<b>ymfhcn(这痞子真帅) </b></font></td><td width="120"><font color="#000000">2006-03-02 08:06:00</font></td><td width="80"><font color="#000000">得分:</font><font color="#000000">0</font></td></tr><tr><td bgcolor="#0066cc" colspan="4" height="1"></td></tr><tr><td colspan="4" height="5"></td></tr><tr><td><font color="#ffffff">?</font></td><td colspan="3"><table style="TABLE-LAYOUT: fixed" cellpadding="3" width="580"><tbody><tr><td><pre><div class="text" readonly="true">creatSQLQuery()是执行sql语句的，不过稍微有些改动，里面什么SQL语句都可以写</div></pre></td></tr></tbody></table><br /><br /><br /> <!--| <a title="Link to the RSS 1.0 feed." href="http://iceling2008.itpub.net/rss/rss10/13270">RSS feed</a>  
| <a title="Link to the Atom feed." href="http://iceling2008.itpub.net/rss/atom/13270">Atom feed</a> -->| = | <a title="1?" href="http://iceling2008.itpub.net/category/13270/23133">一般分类</a> | <a title="0?" href="http://iceling2008.itpub.net/category/13270/23283">仙侠修真</a> | <a title="1?" href="http://iceling2008.itpub.net/category/13270/32971">VBScript</a> | <a title="1?" href="http://iceling2008.itpub.net/category/13270/30764">.NET</a> | <a title="1?" href="http://iceling2008.itpub.net/category/13270/24838">面试题</a> | <a title="1?" href="http://iceling2008.itpub.net/category/13270/24868">存储过程</a> | <a title="1?" href="http://iceling2008.itpub.net/category/13270/23519">Hibernate</a> | <a title="11?" href="http://iceling2008.itpub.net/category/13270/23280">JavaScript</a> | <a title="14?" href="http://iceling2008.itpub.net/category/13270/23155">J2EE</a> | <a title="2?" href="http://iceling2008.itpub.net/category/13270/23134">Struts</a><form id="search" action="http://iceling2008.itpub.net/index.php" method="post"><input size="14" name="searchTerms" /><input type="hidden" value="Search" name="op" /><input type="hidden" value="13270" name="blogId" /><input type="submit" value="搜索" name="Search" /></form><!--end globalNav--><!-- end masthead --><div id="pagecell"><!--pagecell--><div id="leftNav"><div class="relatedLinksTitle">自我介绍</div><div class="relatedLinks">我选择，所以我自由！ <br /></div><div class="relatedLinksTitle">切换风格</div><div class="relatedLinks"><form><center>布局：<select style="WIDTH: 70%" onchange="setActiveLayout(value); &#xA;return false;" size="1"><option value="a" selected="">选择页面布局</option><option value="a">两栏左侧导航（缺省）</option><option value="b">两栏右侧导航</option><option value="c">三栏</option></select></center></form><form><center>配色：<select style="WIDTH: 70%" onchange="setActiveColorSchema(value); &#xA;return false;" size="1"><option value="1" selected="">选择配色方案</option><option value="1">纯净蓝灰（缺省）</option><option value="2">浪漫紫</option><option value="3">清爽绿</option><option value="4">海蓝</option><option value="5">粉红</option></select></center></form><br /><center>提示</center>点击带有"..."标记的栏目可以展开/收拢相应的栏目 
<table width="100%" border="0"><tbody><tr><td class="button" onmousedown="turnonall()" style="CURSOR: pointer">展开所有</td><td class="button" onmousedown="turnoffall()" style="CURSOR: pointer">收拢所有</td></tr></tbody></table></div><div class="relatedLinksTitle">订阅我的Blog</div><div class="relatedLinks" align="center"><a class="nodecoration" title="Link to the RSS 0.90 feed." href="http://iceling2008.itpub.net/rss/rss090/13270"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="RSS 0.90" src="http://blog.itpub.net//templates/ow_ms_v1//img/rss090_logo.gif" /></a><br /><a class="nodecoration" title="Link to the RSS 1.0 feed." href="http://iceling2008.itpub.net/rss/rss10/13270"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="RSS 1.0" src="http://blog.itpub.net//templates/ow_ms_v1//img/rss10_logo.gif" /></a><br /><a class="nodecoration" title="Link to the RSS 2.0 feed." href="http://iceling2008.itpub.net/rss/rss20/13270"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="RSS 2.0" src="http://blog.itpub.net//templates/ow_ms_v1//img/rss20_logo.gif" /></a><br /><a class="nodecoration" title="Link to the Atom 0.3 feed." href="http://iceling2008.itpub.net/rss/atom/13270"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Atom 0.3" src="http://blog.itpub.net//templates/ow_ms_v1//img/atom_logo.png" /></a><br /></div><div class="relatedLinksTitle">博客日历</div><div class="relatedLinks"><center><table class="calMonth"><thead><tr class="calMonthNav"><th class="calMonthBackward"><a title="七月 2006" href="http://iceling2008.itpub.net/archives/13270/200607">«</a></th><th class="calMonthCurrent" colspan="5">八月 2006</th><th class="calMonthForward"><a title="九月 2006" href="http://iceling2008.itpub.net/archives/13270/200609">»</a></th></tr><tr class="calMonthHeader"><th scope="col" abbr="星期一">一</th><th scope="col" abbr="星期二">二</th><th scope="col" abbr="星期三">三</th><th scope="col" abbr="星期四">四</th><th scope="col" abbr="星期五">五</th><th scope="col" abbr="星期六">六</th><th scope="col" abbr="星期日">日</th></tr></thead><tbody><tr><td class="calMonthDay"> </td><td class="calMonthDay">1</td><td class="calMonthDay">2</td><td class="calMonthDay"><a href="http://iceling2008.itpub.net/archives/13270/20060803">3</a></td><td class="calMonthDay">4</td><td class="calMonthDay">5</td><td class="calMonthDay">6</td></tr><tr><td class="calMonthDay">7</td><td class="calMonthDay">8</td><td class="calMonthDay">9</td><td class="calMonthDay">10</td><td class="calMonthDay">11</td><td class="calMonthDay">12</td><td class="calMonthDay">13</td></tr><tr><td class="calMonthDay">14</td><td class="calMonthDay">15</td><td class="calMonthDay">16</td><td class="calMonthDay">17</td><td class="calMonthDay">18</td><td class="calMonthDay">19</td><td class="calMonthDay">20</td></tr><tr><td class="calMonthDay">21</td><td class="calMonthDay">22</td><td class="calMonthDay">23</td><td class="calMonthDay">24</td><td class="calMonthDay">25</td><td class="calMonthDay">26</td><td class="calMonthDay">27</td></tr><tr><td class="calMonthDay">28</td><td class="calMonthDay">29</td><td class="calMonthToday">30</td><td class="calMonthDay">31</td><td class="calMonthDay"> </td><td class="calMonthDay"> </td><td class="calMonthDay"> </td></tr></tbody></table></center></div><div class="relatedLinksTitle" onmousedown="turnswitch('archives')" style="CURSOR: pointer">文章归档...</div><div class="relatedLinks" id="archives" style="DISPLAY: none"><center><a href="http://iceling2008.itpub.net/archives/13270/200608">八月 2006(1篇)</a><br /><a href="http://iceling2008.itpub.net/archives/13270/200607">七月 2006(3篇)</a><br /><a href="http://iceling2008.itpub.net/archives/13270/200606">六月 2006(2篇)</a><br /><a href="http://iceling2008.itpub.net/archives/13270/200605">五月 2006(5篇)</a><br /><a href="http://iceling2008.itpub.net/archives/13270/200604">四月 2006(16篇)</a><br /><a href="http://iceling2008.itpub.net/archives/13270/200603">三月 2006(6篇)</a><br /></center></div><div class="relatedLinksTitle" onmousedown="turnswitch('recentposts')" style="CURSOR: pointer">最新发表...</div><div class="relatedLinks" id="recentposts"><a href="http://iceling2008.itpub.net/post/13270/183972">关闭窗口的好方法！</a><br /><a href="http://iceling2008.itpub.net/post/13270/159272">显示格式为：XX月XX日－XX月XX日（前一个为上周六，后一个为本周五）</a><br /><a href="http://iceling2008.itpub.net/post/13270/147801">修改Web.Config文件的函数(vb.net)</a><br /><a href="http://iceling2008.itpub.net/post/13270/128635">VBScript得到本周的周末日期函数</a><br /><a href="http://iceling2008.itpub.net/post/13270/128457">给定一个日期，计算此日期是一年中的第几周！</a><br /><a href="http://iceling2008.itpub.net/post/13270/97079">javascript中parseInt的问题 </a><br /><a href="http://iceling2008.itpub.net/post/13270/96749">利用javascript得到上周或下周的日期</a><br /><a href="http://iceling2008.itpub.net/post/13270/94929">如何得到前几天的日期</a><br /><a href="http://iceling2008.itpub.net/post/13270/90064">侯捷观点:Java反射机制[转载]</a><br /><a href="http://iceling2008.itpub.net/post/13270/88536">让JSP页面不缓存[设置JSP页面立即过期]</a><br /></div></div><div id="rightNav"><div class="relatedLinksTitle" onmousedown="turnswitch('blog_statistics')" style="CURSOR: pointer">博客统计... </div><div class="relatedLinks" id="blog_statistics" style="DISPLAY: none">总文章数: 33<br />总评论数: 16<br />总引用数: 0<br />总浏览数: 2744<br /></div><div class="relatedLinksTitle" onmousedown="turnswitch('mylinks')" style="CURSOR: pointer">网站链接...</div><div class="myLinks" id="mylinks"><div class="relatedLinksTitle" style="TEXT-ALIGN: left">J2EE</div><div class="relatedLinks"><a class="nodecoration" href="http://community.csdn.net/"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="http://community.csdn.net/" src="http://blog.itpub.net//templates/ow_ms_v1//img/rss_logo_small.gif" /></a><a class="mylink" title="Java Web 开发 Java SUN Java 认证" href="http://community.csdn.net/Expert/FAQ/List_Room_FAQ_Index.asp?bigclassid=54">J2EE&amp;JAVA FAQ</a><br /></div></div><div class="relatedLinksTitle">资源</div><!-- 以下部分的内容，请保留原样， 谢谢！ --><div class="relatedLinks"><table border="0"><tbody><tr><td>Powered by:</td><td><a href="http://www.plogworld.net/"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="pLog" src="http://blog.itpub.net//templates/ow_ms_v1/img/plog-small.gif" /></a></td></tr><tr><td>Blog Provider:</td><td><a href="http://www.itpub.net/"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Itpub" src="http://blog.itpub.net//templates/ow_ms_v1/img/itpub.gif" /></a></td></tr><tr><td>Designed by:</td><td><a href="http://blog.itpub.net/oldwain"><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="oldwain" src="http://blog.itpub.net//templates/ow_ms_v1/img/oldwain.gif" /></a></td></tr><!-- 以上部分的内容，请保留原样， 谢谢！ --><!--
  <tr>
    <td>Modified by:</td>
    <td><a href="http://blog.itpub.net/YOURBLOG"> 您的大名</a></td>
  </tr>
--></tbody></table></div></div><!-- end pagenav --><div id="content"><div class="story"><!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                                   xmlns:dc="http://purl.org/dc/elements/1.1/"
                                   xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"><rdf:Description
                             rdf:about="http://iceling2008.itpub.net/post/13270/64328"
                             dc:identifier="http://iceling2008.itpub.net/post/13270/64328"
                             dc:title="Hibernate 的 session.delete(obj"
                             trackback:ping="http://blog.itpub.net//trackback.php?id=64328"/></rdf:RDF> --><div class="noDisplay">=========================================================== </div><div class="storyTitle">Hibernate 的 session.delete(obj </div><div class="noDisplay">=========================================================== </div><div class="storyInfo">作者: iceling2008(http://iceling2008.itpub.net)<br />发表于:2006.03.30 16:33<br />分类: Hibernate <br />出处：http://iceling2008.itpub.net/post/13270/64328<br />--------------------------------------------------------------- <br /></div><div class="storytext"><p><strong>session.delete(obj)将obj的状态变为transient。两种情况</strong><br />1）obj是session的cache里边的cache没有的，比如：<br />session.delete(new Employee(4));<br />2）obj存在于session的cache中，比如：<br />Employee employee = (Employee)session.load(Employee.class, new Integer(4));<br />session.delete(employee);</p><p>这两种情况都是允许的，hibernate都会发送一条delete语句给数据库。</p><p><strong><font style="BACKGROUND-COLOR: #ff0000" color="#ff0000"><font style="BACKGROUND-COLOR: #ffffff">delete执行之后，如果调用了session.load(), 又可以分为两种情况：</font></font></strong>1）在session.flush()之前，如：<br />tx.beginTransaction();<br />　　　 session.delete(new Employee(4));<br />session.load(Employee.class, new Integer(4));//发生在session.flush()之前<br />tx.commit();<br />那么hibernate会抛出ObjectDeletedException:The object with that id was deleted:</p><p>2）在session.flush()之后，如：<br />tx.beginTransaction();<br />　　　 session.delete(new Employee(4));<br />session.load(Employee.class, new Integer(4));<br />tx.commit();</p><p>tx.beginTransaction();<br />session.load(Employee.class, new Integer(4));//同一个session中，上面的tx.commit()将session flush了一次。<br />tx.commit();<br />那么这个时候hibernate仅仅会抛出ObjectNotFoundException:No row with the give...<br />表示找不到该object。如果第二个tx里边采用session.get()也就不会抛出exception了。</p><p><strong><font color="#ff0000">delete执行之后，如果调用了session.save(obj):</font></strong><br />tx.beginTransaction();<br />Employee employee = (Employee)session.load(Employee.class, new Integer(4)); <br />　　　 session.delete(employee);<br />System.out.println(employee);<br />session.save(employee);<br />System.out.println(employee);<br />tx.commit();<br />这种情况是完全合理的，合法的。<br /><strong>delete将employee从persistent的状态变为transient的状态。<br />save将employee从transient状态变为persistent的状态。</strong><strong>save一个被delete的obj的时候，在save处hibernate强制执行session.flush()，发送delete语句，然后按照常规的save流程来进行。为什么要这么做，还没有完全想明白。<br /><br /><font style="BACKGROUND-COLOR: #ff0000"><font style="BACKGROUND-COLOR: #ffffff" color="#ff0000">delete执行之后，如果对obj对象属性的修改，tx.commit()时不会进行dirtyChecking。</font></font></strong> 这个道理比较显然。</p><p></p><p class="diaryFoot">- 作者： <a onclick="window.open('http://publishblog.blogchina.com/blog/postMessage.b?receiver=47683','发送短消息','width=520, height=455')" href="http://iceling2008.itpub.net/post/13270/void(0);">HairRoot</a> 2005年05月</p></div></div></div></div></td></tr></tbody></table></div>
						</div>
				</div>
		</div>
		<br />
		<br />
		<br />
		<div id="LastMDatecns!8BC51E4BE025FAC0!391">
				<h4 class="TextColor1" id="subjcns!8BC51E4BE025FAC0!391" style="MARGIN-BOTTOM: 0px">hibernate连接sqlserver2000问题的解决</h4>
				<div id="msgcns!8BC51E4BE025FAC0!391">
						<div>这几天在进行数据库的移植,将oracle数据库的东西移植到mssqlserver 2000上</div>
						<div> </div>
						<div>其中运行一个查询的时候,报如下的错误:</div>
						<div> </div>
						<div> [Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode.</div>
						<div> </div>
						<div>
								<font color="#333399">
										<strong>解决办法</strong>:</font>
						</div>
						<div>   &lt;property name="connection.url"&gt;</div>
						<div>     jdbc:microsoft:sqlserver://192.168.1.110:2433;<font color="#ff0000">SelectMethod=cursor</font></div>
						<div>  &lt;/property&gt;</div>
						<div> </div>
						<div>
								<em>
										<u>
												<font color="#333399">(红色为增加的)</font>
										</u>
								</em>
						</div>
						<div>
								<em>
										<u>
												<font color="#333399">
												</font>
										</u>
								</em> </div>
						<div>
								<u>
										<font color="#333399">
												<strong>原因:</strong>
										</font>
								</u>
						</div>
						<div>
								<font color="#000000">   1.    处于手动事务状态,并且使用direct模式,因为hibernate默认为direct模式,</font>
						</div>
						<div>
								<font color="#000000">         即</font>
								<font color="#ff0000">SelectMethod=direct</font>
						</div>
						<div>
								<font color="#ff0000">   </font>
								<font color="#000000">2.    在一个SQL SERVER的JDBC连接上执行多个STATEMENTS的操作</font>
						</div>
				</div>
				<br />
				<br />超强的贴,每句都是经典 
<div id="msgcns!8BC51E4BE025FAC0!375"><div>水至清则无鱼,人至贱则无敌! 走自己的路，让别人打车去吧。穿别人的鞋，走自己的路，让他们找去吧。打台湾我捐一个月的生活费，打美国我捐一年的生活费， 打日本我捐他妈的一条命! 我不是随便的人，我随便起来不是人。女人无所谓正派，正派是因为受到的引诱不够；男人无所谓忠诚，忠诚是因为背叛的筹码太低…… 骑白马的不一定是王子，可能是唐僧；带翅膀的也不一定是天使，有时候是鸟人。 俺的最低奋斗目标：农妇，山泉，有点田。再过几十年，我们来相会，送到火葬场，全部烧成灰，你一堆，我一堆，谁也不认识谁，全部送到农村做化肥<br /><br /><br /><br /><br /><a href="http://iceling2008.itpub.net/category/13270/23134">http://iceling2008.itpub.net/category/13270/23134</a>好东西         阿法萨<br /><a href="http://comsmall.spaces.live.com/PersonalSpace.aspx?_c02_owner=1">http://comsmall.spaces.live.com/PersonalSpace.aspx?_c02_owner=1</a><br /><br /><br /></div></div></div>
		<div id="msgcns!8BC51E4BE025FAC0!391">
				<div>
						<p>
								<font size="2">遇到 "<font color="#c60a00">Automation</font><font color="#c60a00">服务器不能创建对象</font>"</font>
						</p>
						<p>
								<font size="2">运行 Regsvr32 scrrun.dll。</font>
						</p>
				</div>
		</div>
<img src ="http://www.blogjava.net/rendong/aggbug/67339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-09-03 00:37 <a href="http://www.blogjava.net/rendong/archive/2006/09/03/67339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高级 DAO 编程 </title><link>http://www.blogjava.net/rendong/archive/2006/08/31/66964.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Thu, 31 Aug 2006 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/08/31/66964.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/66964.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/08/31/66964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/66964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/66964.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<h1>高级 DAO 编程</h1>
										<p id="subtitle">学习编译更好的 DAO 的技巧</p>
										<img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" />
								</td>
								<td class="no-print" width="192">
										<img height="18" alt="developerWorks" src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" width="192" />
								</td>
						</tr>
				</tbody>
		</table>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td width="100%">
										<table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0">
												<tbody>
														<tr>
																<td width="10">
																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
																</td>
																<td>
																		<table cellspacing="0" cellpadding="0" width="150" border="0">
																				<tbody>
																						<tr>
																								<td class="v14-header-1-small">文档选项</td>
																						</tr>
																				</tbody>
																		</table>
																		<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
																				<tbody>
																						<tr>
																								<td class="no-padding" width="150">
																										<table cellspacing="0" cellpadding="0" width="143" border="0">
																												<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																												<form name="email" action="https://www-128.ibm.com/developerworks/secure/email-it.jsp">
																														<input type="hidden" value="J2EE 开发人员使用数据访问对象(Data Access Object DAO)设计模式，以便将低级别的数据访问逻辑与高级别的业务逻辑分离。实现 DAO 模式涉及比编写数据访问代码更多的内容。在本文中，Java 开发人员 Sean C. Sullivan 讨论了 DAO 编程中三个常常被忽略的方面：事务界定、异常处理和日志记录。" name="body" />
																														<input type="hidden" value="高级 DAO 编程" name="subject" />
																														<input type="hidden" value="cn" name="lang" />
																														<script language="JavaScript" type="text/javascript">
																																<!--
document.write('<tr valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送" /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>将此页作为电子邮件发送</b></a></p></td></tr>');
//-->
																														</script>
																														<tbody>
																																<tr valign="top">
																																		<td width="8">
																																				<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																		</td>
																																		<td width="16">
																																				<img height="16" alt="将此页作为电子邮件发送" src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" />
																																		</td>
																																		<td width="122">
																																				<p>
																																						<a class="smallplainlink" href="javascript:document.email.submit();">
																																								<b>
																																										<font color="#5c81a7" size="2">将此页作为电子邮件发送</font>
																																								</b>
																																						</a>
																																				</p>
																																		</td>
																																</tr>
																																<noscript>
																																		<tr valign="top">
																																				<td width="8">
																																						<img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td width="16">
																																						<img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif" />
																																				</td>
																																				<td class="small" width="122">
																																						<p>
																																								<span class="ast">未显示需要 JavaScript 的文档选项</span>
																																						</p>
																																				</td>
																																		</tr>
																																</noscript>
																														</tbody>
																												</form>
																										</table>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
										<!-- 03/20/06 updated by gretchen -->
										<br />
										<table cellspacing="0" cellpadding="0" width="150" border="0">
												<tbody>
														<tr>
																<td class="v14-header-2-small">最新推荐</td>
														</tr>
												</tbody>
										</table>
										<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td class="no-padding" width="150">
																		<table cellspacing="0" cellpadding="0" width="143" border="0">
																				<tbody>
																						<tr valign="top">
																								<td width="8">
																										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																								</td>
																								<td>
																										<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" />
																								</td>
																								<td width="125">
																										<p>
																												<a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																														<font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																												</a>
																										</p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 初级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#author">
						<font color="#996699">Sean C. Sullivan</font>
				</a>, 软件工程师<br /></p>
		<p>2003 年 10 月 15 日</p>
		<blockquote>J2EE 开发人员使用数据访问对象(Data Access Object DAO)设计模式，以便将低级别的数据访问逻辑与高级别的业务逻辑分离。实现 DAO 模式涉及比编写数据访问代码更多的内容。在本文中，Java 开发人员 Sean C. Sullivan 讨论了 DAO 编程中三个常常被忽略的方面：事务界定、异常处理和日志记录。</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>在过去 18 个月中，我参加了一个由有才华的软件工程师组成的小组，构建定制的、基于 Web 的供应链管理应用程序。我们的应用程序访问范围广泛的持久性数据，包括配送状态、供应链衡量(metrics)、库存、货运发票、项目管理数据和用户信息。我们用 JDBC API 连接到我们公司的不同数据库平台上，并在整个应用程序中使用 DAO 设计模式。</p>
		<p>图 1 显示了应用程序和数据源之间的关系：</p>
		<br />
		<a name="IDAYBMIB">
				<b>图 1. 应用程序和数据源 </b>
		</a>
		<br />
		<img height="176" alt="应用程序和数据源" src="http://www-128.ibm.com/developerworks/cn/java/j-dao/images/jwebapps.jpg" width="282" />
		<br />
		<p>在整个应用程序中使用数据访问对象(DAO)使我们可以将底层数据访问逻辑与业务逻辑分离开来。我们构建了为每一个数据源提供 GRUD (创建、读取、更新、删除)操作的 DAO 类。</p>
		<p>在本文中，我将为您介绍构建更好的 DAO 类的 DAO 实现策略和技术。更确切地说，我将讨论日志、异常处理和事务界定。您将学到如何将这三者结合到自己的 DAO 类中。本文假定您熟悉 JDBC API、SQL 和关系数据库编程。</p>
		<p>我们将以对 DAO 设计模式和数据访问对象的概述开始。</p>
		<p>
				<a name="1">
						<span class="atitle">
								<font face="Arial" size="4">DAO基础</font>
						</span>
				</a>
		</p>
		<p>DAO 模式是标准 J2EE 设计模式之一。开发人员用这种模式将底层数据访问操作与高层业务逻辑分离开。一个典型的 DAO 实现有以下组件：</p>
		<ul>
				<li>一个 DAO 工厂类 
</li>
				<li>一个 DAO 接口 
</li>
				<li>一个实现了 DAO 接口的具体类 
</li>
				<li>数据传输对象(有时称为值对象) </li>
		</ul>
		<p>具体的 DAO 类包含访问特定数据源的数据的逻辑。在下面一节中您将学习设计和实现数据访问对象的技术。有关 DAO 设计模式的更多内容请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#resources"><font color="#996699">参考资料</font></a>。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="2">
						<span class="atitle">
								<font face="Arial" size="4">事务界定</font>
						</span>
				</a>
		</p>
		<p>关于 DAO 要记住的重要一点是它们是事务性对象。由 DAO 所执行的每一个操作 -- 如创建、更新或者删除数据 -- 都与一个事务相关联。因此， <i>事务界定</i>的概念就变得特别重要了。 </p>
		<p>事务界定是定义事务边界的方式。J2EE 规范描述了两种事务界定的模型：编程式(programmatic)和声明式(declarative)。表 1 分析了这两种模型：</p>
		<p>
				<a name="table1">
						<span class="smalltitle">
								<strong>
										<font face="Arial">表 1. 两种事务界定的模型</font>
								</strong>
						</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="3" width="100%" border="1">
				<tbody>
						<tr>
								<td>
										<strong>声明式事务界定</strong>
								</td>
								<td>
										<b>编程式事务界定</b>
								</td>
						</tr>
						<tr>
								<td>程序员用 EJB 部署描述符声明事务属性。</td>
								<td>程序员负责编写事务逻辑。</td>
						</tr>
						<tr>
								<td>运行时环境(EJB 容器)用这些属性自动管理事务。</td>
								<td>应用程序通过一个 API 控制事务。</td>
						</tr>
				</tbody>
		</table>
		<p>我们将侧重于编程式事务界定。</p>
		<p>
				<a name="N100BE">
						<span class="smalltitle">
								<strong>
										<font face="Arial">设计考虑</font>
								</strong>
						</span>
				</a>
		</p>
		<p>如前所述，DAO 是事务性对象。一个典型的 DAO 执行像创建、更新和删除这样的事务性操作。在设计 DAO 时，首先要问自己以下问题：</p>
		<ul>
				<li>事务要如何开始？ 
</li>
				<li>事务应如何结束？ 
</li>
				<li>哪一个对象将负责开始一个事务？ 
</li>
				<li>哪一个对象将负责结束一个事务？ 
</li>
				<li>DAO 是否要负责事务的开始和结束？ 
</li>
				<li>应用程序是否需要通过多个 DAO 访问数据？ 
</li>
				<li>事务涉及到一个 DAO 还是多个 DAO？ 
</li>
				<li>一个 DAO 是否调用另一个 DAO 的方法？ </li>
		</ul>
		<p>了解上述问题的答案将有助于您选择最适合的 DAO 的事务界定策略。在 DAO 中有两种主要的界定事务的策略。一种方式是让 DAO 负责界定事务，另一种将事务界定交给调用这个 DAO 方法的对象处理。如果选择了前一种方式，那么就将事务代码嵌入到 DAO 中。如果选择后一种方式，那么事务界定代码就是在 DAO 类外面。我们将使用简单的代码示例帮助您更好理解每一种方式是如何工作的。</p>
		<p>清单 1 显示了一个有两种数据操作的 DAO：创建和更新：</p>
		<br />
		<a name="IDAMEMIB">
				<b>清单 1. DAO 方法</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">       public void createWarehouseProfile(WHProfile profile);
       public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 2 显示了一个简单的事务。事务界定在 DAO 类外面。注意在这个例子中调用者是如何在一个事务中结合多个 DAO 操作的。</p>
		<br />
		<a name="IDAXEMIB">
				<b>清单 2. 调用者管理的事务</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">      tx.begin();    // start the transaction
      dao.createWarehouseProfile(profile);
      dao.updateWarehouseStatus(id1, status1);
      dao.updateWarehouseStatus(id2, status2);
      tx.commit();   // end the transaction
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这种事务界定策略对于需要在一个事务中访问多个 DAO 的应用程序特别有用。</p>
		<p>可以用 JDBC API 或者 Java 事务 API(Java Transaction API JTA)实现事务界定。 JDBC 事务界定比 JTA 事务界定要简单，但是 JTA 提供了更多的灵活性。在下面一节中我将更深入地分析事务界定的机制。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="3">
						<span class="atitle">
								<font face="Arial" size="4">用 JDBC 进行事务界定</font>
						</span>
				</a>
		</p>
		<p>JDBC 事务是用 <code>Connection</code> 对象控制的。JDBC Connection 接口( <code>java.sql.Connection</code> )提供了两种事务模式：自动提交和手工提交。 <code>java.sql.Connection</code> 提供了以下控制事务的方法： </p>
		<ul>
				<li>
						<code>public void setAutoCommit(boolean)</code>
				</li>
				<li>
						<code>public boolean getAutoCommit()</code>
				</li>
				<li>
						<code>public void commit()</code>
				</li>
				<li>
						<code>public void rollback()</code>
				</li>
		</ul>
		<p>清单 3 显示了如何用 JDBC API 界定一个事务：</p>
		<br />
		<a name="IDAKGMIB">
				<b>清单 3. 用 JDBC API 进行事务界定</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">      import java.sql.*;
      import javax.sql.*;

      // ...
      DataSource ds = obtainDataSource();
      Connection conn = ds.getConnection();
      conn.setAutoCommit(false);
      // ...
      pstmt = conn.prepareStatement("UPDATE MOVIES ...");
      pstmt.setString(1, "The Great Escape");
      pstmt.executeUpdate();
      // ...
      conn.commit();
      // ...
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>使用 JDBC 事务界定时，您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。在下面，我们将看一下如何用 JTA 进行事务界定。因为 JTA 不像 JDBC 那样有名，所以我们首先做一个简介。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="4">
						<span class="atitle">
								<font face="Arial" size="4">JTA简介</font>
						</span>
				</a>
		</p>
		<p>Java 事务 API(JTA) 及其同门兄弟 Java 事务服务(Java Transaction Service JTS)为 J2EE 平台提供了分布式事务服务。一个 <i>分布式的事务</i>涉及一个事务管理器和一个或者多个资源管理器。一个 <i>资源管理器</i>是任何类型的持久性的数据存储。事务管理器负责协调所有事务参与者之间的通信。事务管理器与资源管理器之间的关系如图 2 所示： </p>
		<br />
		<a name="IDADHMIB">
				<b>图 2. 一个事务管理器和资源管理器 </b>
		</a>
		<br />
		<img height="244" alt="一个事务管理器和资源管理器" src="http://www-128.ibm.com/developerworks/cn/java/j-dao/images/transactionmanager.jpg" width="358" />
		<br />
		<p>JTA 事务比 JDBC 事务功能更强。JDBC 事务局限为一个数据库连接，而 JTA 事务可以有多个参与者。所有下列 Java 平台组件都可以参与 JTA 事务：</p>
		<ul>
				<li>JDBC 连接 
</li>
				<li>JDO <code>PersistenceManager</code> 对象 
</li>
				<li>JMS 队列 
</li>
				<li>JMS 主题 
</li>
				<li>企业 JavaBeans 
</li>
				<li>符合 J2EE 连接体系结构(J2EE Connector Architecture)规范的资源适配器 </li>
		</ul>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="5">
						<span class="atitle">
								<font face="Arial" size="4">使用 JTA 的事务界定</font>
						</span>
				</a>
		</p>
		<p>要用 JTA 进行事务界定，应用程序要调用 <code>javax.transaction.UserTransaction</code> 接口中的方法。清单 4 显示了对 <code>UserTransaction</code> 对象的典型 JNDI 查询： </p>
		<br />
		<a name="IDAQQMIB">
				<b>清单 4. 一个对 UserTransaction 对象的 JDNI 查询</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">      import javax.transaction.*;
      import javax.naming.*;
      // ...
      InitialContext ctx = new InitialContext();
      Object txObj = ctx.lookup("java:comp/UserTransaction");
      UserTransaction utx = (UserTransaction) txObj;

</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>当应用程序找到了 <code>UserTransaction </code>对象后，就可以开始事务了，如清单 5 所示： </p>
		<br />
		<a name="IDAARMIB">
				<b>清单 5. 用 JTA 开始一个事务</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">      utx.begin();
      // ...
      DataSource ds = obtainXADataSource();
      Connection conn = ds.getConnection();
      pstmt = conn.prepareStatement("UPDATE MOVIES ...");
      pstmt.setString(1, "Spinal Tap");
      pstmt.executeUpdate();
      // ...
      utx.commit();
      // ...

</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>当应用程序调用 <code>commit()</code> 时，事务管理器用一个两阶段的提交协议结束事务。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="6">
						<span class="atitle">
								<font face="Arial" size="4">控制事务的 JTA 方法</font>
						</span>
				</a>
		</p>
		<p>
				<code>javax.transaction.UserTransaction</code> 接口提供了以下事务控制方法： </p>
		<ul>
				<li>
						<code>public void begin()</code>
				</li>
				<li>
						<code>public void commit()</code>
				</li>
				<li>
						<code>public void rollback()</code>
				</li>
				<li>
						<code>public int getStatus()</code>
				</li>
				<li>
						<code>public void setRollbackOnly()</code>
				</li>
				<li>
						<code>public void setTransactionTimeout(int)</code>
				</li>
		</ul>
		<p>应用程序调用 <code>begin()</code> 开始事务。应用程序调用 <code>commit()</code> 或者 <code>rollback()</code> 结束事务。参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#resources"><font color="#996699">参考资料</font></a>以了解更多关于用 JTA 进行事务管理的内容。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="7">
						<span class="atitle">
								<font face="Arial" size="4">使用 JTA 和 JDBC</font>
						</span>
				</a>
		</p>
		<p>开发人员通常在 DAO 类中用 JDBC 进行底层数据操作。如果计划用 JTA 界定事务，那么就需要有一个实现 <code>javax.sql.XADataSource</code> 、 <code>javax.sql.XAConnection </code>和 <code>javax.sql.XAResource</code> 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 <code>XADataSource</code> 对象就是一个 <code>XAConnection</code> 对象的工厂。 <code>XAConnection</code> s 是参与 JTA 事务的 JDBC 连接。 </p>
		<p>您将需要用应用服务器的管理工具设置 <code>XADataSource</code> 。从应用服务器和 JDBC 驱动程序的文档中可以了解到相关的指导。 </p>
		<p>J2EE 应用程序用 JNDI 查询数据源。一旦应用程序找到了数据源对象，它就调用 <code>javax.sql.DataSource.getConnection()</code> 以获得到数据库的连接。 </p>
		<p>XA 连接与非 XA 连接不同。一定要记住 XA 连接参与了 JTA 事务。这意味着 XA 连接不支持 JDBC 的自动提交功能。同时，应用程序一定不要对 XA 连接调用 <code>java.sql.Connection.commit()</code> 或者 <code>java.sql.Connection.rollback()</code> 。相反，应用程序应该使用 <code>UserTransaction.begin()、</code><code>UserTransaction.commit()</code> 和 <code>serTransaction.rollback()</code> 。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="8">
						<span class="atitle">
								<font face="Arial" size="4">选择最好的方式</font>
						</span>
				</a>
		</p>
		<p>我们讨论了如何用 JDBC 和 JTA 界定事务。每一种方式都有其优点，您需要决定哪一种最适合于您的应用程序。</p>
		<p>在最近的许多项目中，我们小组是用 JDBC API 进事务界定来构建 DAO 类的。这些 DAO 类可以总结如下：</p>
		<ul>
				<li>事务界定代码嵌入在 DAO 类中。 
</li>
				<li>DAO 类使用 JDBC API 进行事务界定。 
</li>
				<li>调用者不能界定事务。 
</li>
				<li>事务范围局限于单个 JDBC 连接。 </li>
		</ul>
		<p>JDBC 事务并不总是适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库，那么下列实现策略也许更合适：</p>
		<ul>
				<li>事务用 JTA 界定。 
</li>
				<li>事务界定代码从 DAO 中分离出来。 
</li>
				<li>调用者负责界定事务。 
</li>
				<li>DAO 加入一个全局事务。 </li>
		</ul>
		<p>JDBC 方式由于其简单性而具有吸引力，JTA　方式提供了更大的灵活性。您所选择的实现将取决于应用程序的特定需求。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="9">
						<span class="atitle">
								<font face="Arial" size="4">日志记录和 DAO</font>
						</span>
				</a>
		</p>
		<p>一个良好实现的 DAO 类将使用日志记录来捕捉有关其运行时行为的细节。您可以选择记录异常、配置信息、连接状态、JDBC 驱动程序元数据、或者查询参数。日志对于开发的所有阶段都很有用。我经常在开发时、测试时和生产中分析应用程序日志。</p>
		<p>在本节，我将展示一个显示如何将 Jakarta Commons Logging 加入到 DAO 中的代码示例。在这之前，让我们回顾一下一些基本知识。</p>
		<p>
				<a name="N10285">
						<span class="smalltitle">
								<strong>
										<font face="Arial">选择日志库</font>
								</strong>
						</span>
				</a>
		</p>
		<p>许多开发人员使用一种原始格式进行日志记录： <code>System.out.println</code> 和 <code>System.err.println</code> 。 <code>Println</code> 语句速度快且使用方便，但是它们没有提供全功能的日志记录系统所具有的功能。表 2 列出了 Java 平台的日志库： </p>
		<p>
				<a name="table2">
						<span class="smalltitle">
								<strong>
										<font face="Arial">表 2. Java 平台的日志库</font>
								</strong>
						</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="3" width="100%" border="1">
				<tbody>
						<tr>
								<td>
										<strong>日志库</strong>
								</td>
								<td>
										<b>开放源代码？</b>
								</td>
								<td>
										<b>URL</b>
								</td>
						</tr>
						<tr>
								<td>java.util.logging</td>
								<td>不是</td>
								<td>http://java.sun.com/j2se/</td>
						</tr>
						<tr>
								<td>Jakarta Log4j</td>
								<td>是</td>
								<td>http://jakarta.apache.org/log4j/</td>
						</tr>
						<tr>
								<td>Jakarta Commons Logging</td>
								<td>是</td>
								<td>http://jakarta.apache.org/commons/logging.html</td>
						</tr>
				</tbody>
		</table>
		<p>Jakarta Commons Logging 可以与 <code>java.util.logging</code> 或者 Jakarta Log4j 一同使用。Commons Logging 是一个日志抽象层，它隔离了应用程序与底层日志实现。使用 Commons Logging，您可以通过改变配置文件更换底层日志实现。Commons Logging 在 Jakarta Struts 1.1 和 Jakarta HttpClient 2.0 中使用。 </p>
		<p>
				<a name="N102EA">
						<span class="smalltitle">
								<strong>
										<font face="Arial">一个日志记录示例</font>
								</strong>
						</span>
				</a>
		</p>
		<p>清单 7 显示了如何在 DAO 类中使用 Jakarta Commons Logging：</p>
		<br />
		<a name="IDAOYMIB">
				<b>清单 7. DAO 类中的 Jakarta Commons Logging</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">import org.apache.commons.logging.*;

class DocumentDAOImpl implements DocumentDAO
{
      static private final Log log = LogFactory.getLog(DocumentDAOImpl.class);

      public void deleteDocument(String id)
      {
          // ...
          log.debug("deleting document: " + id);
          // ...
          try
          {
              // ... data operations ...
          }
          catch (SomeException ex)
          {
              log.error("Unable to delete document", ex);
              // ... handle the exception ...
	}
      }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>日志记录是所有任务关键型应用程序的重要部分。如果在 DAO 中遇到故障，那么日志通常可以提供判断出错位置的最好信息。将日志加入到 DAO 可以保证您有机会进行调试和故障排除。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="10">
						<span class="atitle">
								<font face="Arial" size="4">DAO 中的异常处理</font>
						</span>
				</a>
		</p>
		<p>我们讨论过了事务界定和日志，现在对于如何在数据访问对象上应用它们有了更深入的理解。我们的第三个和最后一个讨论议题是异常处理。遵从几个简单的异常处理指导可以使您的 DAO 更容易使用、更健壮及更易于维护。</p>
		<p>在实现 DAO 模式时，考虑以下问题：</p>
		<ul>
				<li>DAO 的公共接口中的方法是否抛出检查过的异常？ 
</li>
				<li>如果是的话，抛出何种检查过的异常？ 
</li>
				<li>在 DAO 实现类中如何处理异常？ </li>
		</ul>
		<p>在使用 DAO 模式的过程中，我们的小组开发了一些处理异常的原则。遵从这些原则可以极大地改进您的 DAO：</p>
		<ul>
				<li>DAO 方法应该抛出有意义的异常。 
</li>
				<li>DAO 方法不应该抛出 <code>java.lang.Exception</code> 。 <code>java.lang.Exception</code> 太一般化了。它不传递关于底层问题的任何信息。 <br /></li>
				<li>DAO 方法不应该抛出 <code>java.sql.SQLException</code> 。SQLException 是一个低级别的 JDBC 异常。一个 DAO 应该力争封装 JDBC 而不是将 JDBC 公开给应用程序的其余部分。 <br /></li>
				<li>只有在可以合理地预期调用者可以处理异常时，DAO 接口中的方法才应该抛出检查过的异常。如果调用者不能以有意义的方式处理这个异常，那么考虑抛出一个未检查的(运行时)异常。 
</li>
				<li>如果数据访问代码捕获了一个异常，不要忽略它。忽略捕获的异常的 DAO 是很难进行故障诊断的。 
</li>
				<li>使用链接的异常将低级别的异常转化为高级别的异常。 
</li>
				<li>考虑定义标准 DAO 异常类。Spring Framework (参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#Resources"><font color="#996699">参考资料</font></a>)提供了很好的一套预定义的 DAO 异常类。 </li>
		</ul>
		<p>有关异常和异常处理技术的更多信息参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#resources"><font color="#996699">参考资料</font></a>。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="11">
						<span class="atitle">
								<font face="Arial" size="4">实现实例： MovieDAO</font>
						</span>
				</a>
		</p>
		<p>
				<code>MovieDAO</code> 是一个展示本文中讨论的所有技术的 DAO：事务界定、日志和异常处理。您可以在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-dao/#Resources"><font color="#996699">参考资料</font></a>一节中找到 <code>MovieDAO</code> 源代码。代码分为三个包： </p>
		<ul>
				<li>
						<code>daoexamples.exception</code>
				</li>
				<li>
						<code>daoexamples.movie</code>
				</li>
				<li>
						<code>daoexamples.moviedemo</code>
				</li>
		</ul>
		<p>DAO 模式的这个实现包含下面列出的类和接口：</p>
		<ul>
				<li>
						<code>daoexamples.movie.MovieDAOFactory</code>
				</li>
				<li>
						<code>daoexamples.movie.MovieDAO</code>
				</li>
				<li>
						<code>daoexamples.movie.MovieDAOImpl</code>
				</li>
				<li>
						<code>daoexamples.movie.MovieDAOImplJTA</code>
				</li>
				<li>
						<code>daoexamples.movie.Movie</code>
				</li>
				<li>
						<code>daoexamples.movie.MovieImpl</code>
				</li>
				<li>
						<code>daoexamples.movie.MovieNotFoundException</code>
				</li>
				<li>
						<code>daoexamples.movie.MovieUtil</code>
				</li>
		</ul>
		<p>
				<code>MovieDAO</code> 接口定义了 DAO 的数据操作。这个接口有五个方法，如下所示： </p>
		<ul>
				<li>
						<code>public Movie findMovieById(String id)</code>
				</li>
				<li>
						<code>public java.util.Collection findMoviesByYear(String year)</code>
				</li>
				<li>
						<code>public void deleteMovie(String id)</code>
				</li>
				<li>
						<code>public Movie createMovie(String rating, String year, String, title)</code>
				</li>
				<li>
						<code>public void updateMovie(String id, String rating, String year, String title)</code>
				</li>
		</ul>
		<p>
				<code>daoexamples.movie</code> 包包含 <code>MovieDAO</code> 接口的两个实现。每一个实现使用一种不同的方式进行事务界定，如表 3 所示： </p>
		<p>
				<a name="table3">
						<span class="smalltitle">
								<strong>
										<font face="Arial">表 3. MovieDAO 实现</font>
								</strong>
						</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="3" width="100%" border="1">
				<tbody>
						<tr>
								<td>
										<strong>
												<font face="Arial">
												</font>
										</strong>
								</td>
								<td>
										<strong>MovieDAOImpl</strong>
								</td>
								<td>
										<b>MovieDAOImplJTA</b>
								</td>
						</tr>
						<tr>
								<td>实现 MovieDAO 接口?</td>
								<td>是</td>
								<td>是</td>
						</tr>
						<tr>
								<td>通过 JNDI 获得 DataSource？</td>
								<td>是</td>
								<td>是</td>
						</tr>
						<tr>
								<td>从 DataSource 获得 java.sql.Connection 对象？</td>
								<td>是</td>
								<td>是</td>
						</tr>
						<tr>
								<td>DAO 在内部界定事务？</td>
								<td>是</td>
								<td>否</td>
						</tr>
						<tr>
								<td>使用 JDBC 事务？</td>
								<td>是</td>
								<td>否</td>
						</tr>
						<tr>
								<td>使用一个 XA DataSource？</td>
								<td>否</td>
								<td>是</td>
						</tr>
						<tr>
								<td>参与 JTA 事务？</td>
								<td>否</td>
								<td>是</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N10466">
						<span class="smalltitle">
								<strong>
										<font face="Arial">MovieDAO 演示应用程序</font>
								</strong>
						</span>
				</a>
		</p>
		<p>这个演示应用程序是一个名为 <code>daoexamples.moviedemo.DemoServlet</code> 的 servlet 类。 <code>DemoServlet</code> 使用这两个 Movie DAO 查询和更新表中的电影数据。 </p>
		<p>这个 servlet 展示了如何将支持 JTA 的 <code>MovieDAO</code> 和 Java 消息服务(Java Message Service)结合到一个事务中，如清单 8 所示。 </p>
		<br />
		<a name="IDADANIB">
				<b>清单 8. 将 MovieDAO 和 JMS 代码结合到一个事务中</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">	UserTransaction utx = MovieUtil.getUserTransaction();
	utx.begin();
	batman = dao.createMovie("R",
			"2008",
			"Batman Reloaded");
	publisher = new MessagePublisher();
	publisher.publishTextMessage("I'll be back");
	dao.updateMovie(topgun.getId(),
			"PG-13",
			topgun.getReleaseYear(),
			topgun.getTitle());
	dao.deleteMovie(legallyblonde.getId());
	utx.commit();
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/rendong/aggbug/66964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-08-31 23:16 <a href="http://www.blogjava.net/rendong/archive/2006/08/31/66964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>权限＋DAO</title><link>http://www.blogjava.net/rendong/archive/2006/08/31/66954.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Thu, 31 Aug 2006 14:36:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/08/31/66954.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/66954.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/08/31/66954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/66954.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/66954.html</trackback:ping><description><![CDATA[
		<p> 当前位置: 首页 &gt;&gt; 数据库 &gt;&gt; Oracle &gt;&gt; 我的权限控制(JBX + struts + hibernate + ORACLE) <br /> <br />我的权限控制(JBX + struts + hibernate + ORACLE)  </p>
		<p>--------------------------------------------------------------------------------<br /> <br />作者：:     来源：     发表时间：2006-06-08     浏览次数：18    字号：大  中  小 <br />　　 <br />通过过滤器判断用户权限.<br />第一步:建立UserPermissionFilter类.</p>
		<p>
				<br />import javax.servlet.*;<br />import javax.servlet.http.*;<br />import java.io.*;<br />import java.util.*;</p>
		<p>import test.system.SysUserApi;<br />import test.vo.SysUserVO;<br />import test.system.dao.SysUserDao;<br />import test.Const;</p>
		<p>public class UserPermissionFilter extends HttpServlet implements Filter {</p>
		<p>  protected FilterConfig filterConfig = null;</p>
		<p>  public void destroy() {<br />    this.filterConfig = null;<br />  }</p>
		<p>
				<br />  public void doFilter(<br />      ServletRequest request,<br />      ServletResponse response,<br />      FilterChain filterChain) throws IOException, ServletException {<br />    try {<br />      HttpServletRequest req = (HttpServletRequest) request;<br />      SysUserVO userSession = new SysUserVO();<br />      userSession = (SysUserVO)req.getSession().getAttribute(Const.SESSION_USER);<br />      if (userSession == null) {<br />        HttpServletResponse rep = (HttpServletResponse) response;</p>
		<p>        rep.sendRedirect("/admin/login.jsp");<br />             }else{<br />        filterChain.doFilter(request, response);<br />      }<br />    }<br />    catch (Exception e) {}<br />  }<br />  public void init(FilterConfig filterConfig) throws ServletException {<br />    this.filterConfig = filterConfig;<br />  }<br />  public FilterConfig getFilterConfig() {<br />    return filterConfig;<br />  }</p>
		<p>  public void setFilterConfig(FilterConfig filterConfig) {<br />    this.filterConfig = filterConfig;<br />  }</p>
		<p>}</p>
		<p>
				<br />第二步:配置WEB.xml文件<br />设置过滤器:<br />  &lt;filter&gt;<br />    &lt;filter-name&gt;userpermission&lt;/filter-name&gt;<br />    &lt;filter-class&gt;sports.tools.UserPermissionFilter&lt;/filter-class&gt;<br />  &lt;/filter&gt;<br />设置过滤器映射,因为过滤器不能过滤全部的程序,所以可以用列表的形式来增加需要过滤的文件.如下.一个过滤器可以过滤多个映射文件.<br />  &lt;filter-mapping&gt;<br />    &lt;filter-name&gt;userpermission&lt;/filter-name&gt;<br />    &lt;url-pattern&gt;/admin/index.jsp&lt;/url-pattern&gt;<br />  &lt;/filter-mapping&gt;</p>
		<p>  &lt;filter-mapping&gt;<br />    &lt;filter-name&gt;userpermission&lt;/filter-name&gt;<br />    &lt;url-pattern&gt;/admin/edit/*&lt;/url-pattern&gt;<br />  &lt;/filter-mapping&gt; <br /> <br /> <br /> <br />======================================<br /><a href="http://www.itwenzhai.com/data/2006/0608/article_22958.htm">http://www.itwenzhai.com/data/2006/0608/article_22958.htm</a><br />=========================================<br /><a href="http://www.itwenzhai.com/data/2006/0626/article_25178.htm">http://www.itwenzhai.com/data/2006/0626/article_25178.htm</a><br />=========================================</p>
		<p>
				<br />  不重复DAO<br />===============</p>
		<p> </p>
		<p>由于 Java™ 5 泛型的采用，有关泛型类型安全 Data Access Object (DAO) 实现的想法变得切实可行。在本文中，系统架构师 Per Mellqvist 展示了基于 Hibernate 的泛型 DAO 实现类。然后展示如何使用 Spring AOP introductions 将类型安全接口添加到类中以便于查询执行。<br />对于大多数开发人员，为系统中的每个 DAO 编写几乎相同的代码到目前为止已经成为一种习惯。虽然所有人都将这种重复标识为 “代码味道”，但我们大多数都已经学会忍受它。其实有解决方案。可以使用许多 ORM 工具来避免代码重复。例如，使用 Hibernate，您可以简单地为所有的持久域对象直接使用会话操作。这种方法的缺点是损失了类型安全。</p>
		<p>为什么您要为数据访问代码提供类型安全接口？我会争辩说，当它与现代 IDE 工具一起使用时，会减少编程错误并提高生产率。首先，类型安全接口清楚地指明哪些域对象具有可用的持久存储。其次，它消除了易出错的类型强制转换的需要（这是一个在查询操作中比在 CRUD 中更常见的问题）。最后，它有效利用了今天大多数 IDE 具备的自动完成特性。使用自动完成是记住什么查询可用于特定域类的快捷方法。</p>
		<p>在本文中，我将为您展示如何避免再三地重复 DAO 代码，而仍保留类型安全接口的优点。事实上，您需要为每个新 DAO 编写的只是 Hibernate 映射文件、无格式旧 Java 接口以及 Spring 配置文件中的 10 行。</p>
		<p>DAO 实现</p>
		<p>DAO 模式对任何企业 Java 开发人员来说都应该很熟悉。但是模式的实现各不相同，所以我们来澄清一下本文提供的 DAO 实现背后的假设：</p>
		<p>系统中的所有数据库访问都通过 DAO 进行以实现封装。 <br />每个 DAO 实例负责一个主要域对象或实体。如果域对象具有独立生命周期，它应具有自己的 DAO。 <br />DAO 负责域对象的创建、读取（按主键）、更新和删除（creations, reads, updates, and deletions，CRUD）。 <br />DAO 可允许基于除主键之外的标准进行查询。我将之称为查找器方法 或查找器。查找器的返回值通常是 DAO 负责的域对象集合。 <br />DAO 不负责处理事务、会话或连接。这些不由 DAO 处理是为了实现灵活性。 <br />泛型 DAO 接口</p>
		<p>泛型 DAO 的基础是其 CRUD 操作。下面的接口定义泛型 DAO 的方法：</p>
		<p>
				<br />清单 1. 泛型 DAO 接口<br />public interface GenericDao &lt;T, PK extends Serializable&gt; {</p>
		<p>    /** Persist the newInstance object into database */<br />    PK create(T newInstance);</p>
		<p>    /** Retrieve an object that was previously persisted to the database using<br />     *   the indicated id as primary key<br />     */<br />    T read(PK id);</p>
		<p>    /** Save changes made to a persistent object.  */<br />    void update(T transientObject);</p>
		<p>    /** Remove an object from persistent storage in the database */<br />    void delete(T persistentObject);<br />}</p>
		<p> </p>
		<p>
				<br />实现接口</p>
		<p>用 Hibernate 实现清单 1 中的接口十分简单，如清单 2 所示。它只需调用底层 Hibernate 方法和添加强制类型转换。Spring 负责会话和事务管理。（当然，我假设这些函数已做了适当的设置，但该主题在 Hibernate 和 Springt 手册中有详细介绍。）</p>
		<p>
				<br />清单 2. 第一个泛型 DAO 实现<br />public class GenericDaoHibernateImpl &lt;T, PK extends Serializable&gt;<br />    implements GenericDao&lt;T, PK&gt;, FinderExecutor {<br />    private Class&lt;T&gt; type;</p>
		<p>    public GenericDaoHibernateImpl(Class&lt;T&gt; type) {<br />        this.type = type;<br />    }</p>
		<p>    public PK create(T o) {<br />        return (PK) getSession().save(o);<br />    }</p>
		<p>    public T read(PK id) {<br />        return (T) getSession().get(type, id);<br />    }</p>
		<p>    public void update(T o) {<br />        getSession().update(o);<br />    }</p>
		<p>    public void delete(T o) {<br />        getSession().delete(o);<br />    }</p>
		<p>    // Not showing implementations of getSession() and setSessionFactory()<br />            }<br /> </p>
		<p>
				<br />Spring 配置</p>
		<p>最后，在 Spring 配置中，我创建了 GenericDaoHibernateImpl 的一个实例。必须告诉 GenericDaoHibernateImpl 的构造函数 DAO 实例将负责哪个域类。只有这样，Hibernate 才能在运行时知道由 DAO 管理的对象类型。在清单 3 中，我将域类 Person 从示例应用程序传递给构造函数，并将先前配置的 Hibernate 会话工厂设置为已实例化的 DAO 的参数：</p>
		<p>
				<br />清单 3. 配置 DAO<br />&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 />         <br />2。<br />我还没有完成，但我所完成的确实已经可以使用了。在清单 4 中，可以看到原封不动使用该泛型 DAO 的示例：</p>
		<p>
				<br />清单 4. 使用 DAO<br />public void someMethodCreatingAPerson() {<br />    ...<br />    GenericDao dao = (GenericDao)<br />     beanFactory.getBean("personDao"); // This should normally be injected</p>
		<p>    Person p = new Person("Per", 90);<br />    dao.create(p);<br />}<br />         </p>
		<p> </p>
		<p>现在，我有一个能够进行类型安全 CRUD 操作的泛型 DAO。让子类 GenericDaoHibernateImpl 为每个域对象添加查询能力将非常合理。因为本文的目的在于展示如何不为每个查询编写显式的 Java 代码来实现查询，但是，我将使用其他两个工具将查询引入 DAO，也就是 Spring AOP 和 Hibernate 命名的查询。</p>
		<p>Spring AOP introductions</p>
		<p>可以使用 Spring AOP 中的 introductions 将功能添加到现有对象，方法是将功能包装在代理中，定义应实现的接口，并将所有先前未支持的方法指派到单个处理程序。在我的 DAO 实现中，我使用 introductions 将许多查找器方法添加到现有泛型 DAO 类中。因为查找器方法是特定于每个域对象的，因此将其应用于泛型 DAO 的类型化接口。</p>
		<p>Spring 配置如清单 5 所示：</p>
		<p>
				<br />清单 5. FinderIntroductionAdvisor 的 Spring 配置<br />&lt;bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/&gt;</p>
		<p>&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;</p>
		<p>&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 />         </p>
		<p> </p>
		<p>在清单 5 的配置文件中，我定义了三个 Spring bean。第一个 bean 是 FinderIntroductionAdvisor，它处理引入到 DAO 的所有方法，这些方法在 GenericDaoHibernateImpl 类中不可用。我稍后将详细介绍 Advisor bean。</p>
		<p>第二个 bean 是 “抽象的”。在 Spring 中，这意味着该 bean 可在其他 bean 定义中被重用，但不被实例化。除了抽象特性之外，该 bean 定义只指出我想要 GenericDaoHibernateImpl 的实例以及该实例需要对 SessionFactory 的引用。注意，GenericDaoHibernateImpl 类仅定义一个构造函数，该构造函数接受域类作为其参数。因为该 bean 定义是抽象的，所以我将来可以无数次地重用该定义，并将构造函数参数设置为合适的域类。</p>
		<p>最后，第三个也是最有趣的 bean 将 GenericDaoHibernateImpl 的 vanilla 实例包装在代理中，赋予其执行查找器方法的能力。该 bean 定义也是抽象的，不指定希望引入到 vanilla DAO 的接口。该接口对于每个具体的实例是不同的。注意，清单 5 显示的整个配置仅定义一次。</p>
		<p>3。</p>
		<p>扩展 GenericDAO</p>
		<p>当然，每个 DAO 的接口都基于 GenericDao 接口。我只需使该接口适应特定的域类并扩展该接口以包括查找器方法。在清单 6 中，可以看到为特定目的扩展的 GenericDao 接口示例：</p>
		<p>
				<br />清单 6. PersonDao 接口<br />public interface PersonDao extends GenericDao&lt;Person, Long&gt; {<br />    List&lt;Person&gt; findByName(String name);<br />}</p>
		<p> </p>
		<p> </p>
		<p>很明显，清单 6 中定义的方法旨在按名称查找 Person。必需的 Java 实现代码全部是泛型代码，在添加更多 DAO 时不需要任何更新。</p>
		<p>配置 PersonDao</p>
		<p>因为 Spring 配置依赖于先前定义的 “抽象” bean，因此它变得相当简洁。我需要指出 DAO 负责哪个域类，并且需要告诉 Springs 该 DAO 应实现哪个接口（一些方法是直接使用，一些方法则是通过使用 introductions 来使用）。清单 7 展示了 PersonDAO 的 Spring 配置文件：</p>
		<p>
				<br />清单 7. PersonDao 的 Spring 配置<br />&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 />         </p>
		<p> </p>
		<p>在清单 8 中，可以看到使用了这个更新后的 DAO 版本：</p>
		<p>
				<br />清单 8. 使用类型安全接口<br />public void someMethodCreatingAPerson() {<br />    ...<br />    PersonDao dao = (PersonDao)<br />     beanFactory.getBean("personDao"); // This should normally be injected</p>
		<p>    Person p = new Person("Per", 90);<br />    dao.create(p);</p>
		<p>    List&lt;Person&gt; result = dao.findByName("Per"); // Runtime exception<br />}<br />         </p>
		<p> </p>
		<p>虽然清单 8 中的代码是使用类型安全 PersonDao 接口的正确方法，但 DAO 的实现并不完整。调用 findByName() 会导致运行时异常。问题在于我还没有实现调用 findByName() 所必需的查询。剩下要做的就是指定查询。为更正该问题，我使用了 Hibernate 命名查询。</p>
		<p>
				<br /> </p>
		<p>Hibernate 命名查询</p>
		<p>使用 Hibernate，可以在 Hibernate 映射文件 (hbm.xml) 中定义 HQL 查询并为其命名。稍后可以通过简单地引用给定名称来在 Java 代码中使用该查询。该方法的优点之一是能够在部署时优化查询，而无需更改代码。您一会将会看到，另一个优点是无需编写任何新 Java 实现代码，就可以实现 “完整的” DAO。清单 9 是带有命名查询的映射文件的示例：</p>
		<p>
				<br />清单 9. 带有命名查询的映射文件<br /> &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;</p>
		<p>     &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 />         </p>
		<p> </p>
		<p>清单 9 定义了域类 Person 的 Hibernate 映射，该域类具有两个属性：name 和 weight。Person 是具有上述属性的简单 POJO。该文件还包含一个在数据库中查找 Person 所有实例的查询，其中 “name” 等于提供的参数。Hibernate 不为命名查询提供任何真正的名称空间功能。出于讨论目的，我为所有查询名称都加了域类的短（非限定）名称作为前缀。在现实世界中，使用包括包名称的完全类名可能是更好的主意。</p>
		<p>
				<br /> </p>
		<p>逐步概述</p>
		<p>您已经看到了为任何域对象创建和配置新 DAO 所必需的全部步骤。三个简单的步骤是：</p>
		<p>定义一个接口，它扩展 GenericDao 并包含所需的任何查找器方法。 <br />将每个查找器的命名查询添加到域对象的 hbm.xml 映射文件。 <br />为 DAO 添加 10 行 Spring 配置文件。 <br />查看执行查找器方法的代码（只编写了一次！）来结束我的讨论。</p>
		<p>4。</p>
		<p>可重用的 DAO 类</p>
		<p>使用的 Spring advisor 和 interceptor 很简单，事实上它们的工作是向后引用 GenericDaoHibernateImplClass。方法名以 “find” 打头的所有调用都传递给 DAO 和单个方法 executeFinder()。</p>
		<p>
				<br />清单 10. FinderIntroductionAdvisor 的实现<br />public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {<br />    public FinderIntroductionAdvisor() {<br />        super(new FinderIntroductionInterceptor());<br />    }<br />}</p>
		<p>public class FinderIntroductionInterceptor implements IntroductionInterceptor {</p>
		<p>    public Object invoke(MethodInvocation methodInvocation) throws Throwable {</p>
		<p>        FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();</p>
		<p>        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 />    }</p>
		<p>    public boolean implementsInterface(Class intf) {<br />        return intf.isInterface() &amp;&amp; FinderExecutor.class.isAssignableFrom(intf);<br />    }<br />}<br /> </p>
		<p> </p>
		<p>executeFinder() 方法</p>
		<p>清单 10 的实现中惟一缺少的是 executeFinder() 实现。该代码查看调用的类和方法的名称，并使用配置上的约定将其与 Hibernate 查询的名称相匹配。还可以使用 FinderNamingStrategy 来支持其他命名查询的方法。默认实现查找叫做 “ClassName.methodName” 的查询，其中 ClassName 是不带包的短名称。清单 11 完成了泛型类型安全 DAO 实现： </p>
		<p>
				<br />清单 11. executeFinder() 的实现<br />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 /> }</p>
		<p> public String queryNameFromMethod(Method finderMethod) {<br />     return type.getSimpleName() + "." + finderMethod.getName();<br /> }<br /> </p>
		<p> </p>
		<p>结束语</p>
		<p>在 Java 5 之前，该语言不支持编写既类型安全又 泛型的代码，您必须只能选择其中之一。在本文中，您已经看到一个结合使用 Java 5 泛型与 Spring 和 Hibernate（以及 AOP）等工具来提高生产率的示例。泛型类型安全 DAO 类相当容易编写 —— 您只需要单个接口、一些命名查询和为 Spring 配置添加的 10 行代码 —— 而且可以极大地减少错误并节省时间。</p>
		<p>几乎本文的所有代码都是可重用的。尽管您的 DAO 类可能包含此处没有实现的查询和操作类型（比如，批操作），但使用我所展示的技术，您至少应该能够实现其中的一部分。参阅 参考资料 了解其他泛型类型安全 DAO 类实现。</p>
		<p>致谢</p>
		<p>自 Java 语言中出现泛型以来，单个泛型类型安全 DAO 的概念已经成为主题。我曾在 JavaOne 2004 中与 Don Smith 简要讨论了泛型 DAO 的灵活性。本文使用的 DAO 实现类旨在作为示例实现，实际上还存在其他实现。例如，Christian Bauer 已经发布了带有 CRUD 操作和标准搜索的实现，Eric Burke 也在该领域做出了工作。我确信将会有更多的实现出现。我要额外感谢 Christian，他目睹了我编写泛型类型安全 DAO 的第一次尝试并提出改进建议。最后，我要感谢 Ramnivas Laddad 的无价帮助，他审阅了本文。</p>
		<p> </p>
<img src ="http://www.blogjava.net/rendong/aggbug/66954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-08-31 22:36 <a href="http://www.blogjava.net/rendong/archive/2006/08/31/66954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring+Hibernate+Struts配置(转载 http://www.blogjava.net/envoydada/archive/2006/07/24/45438.html)</title><link>http://www.blogjava.net/rendong/archive/2006/08/01/61208.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Tue, 01 Aug 2006 07:06:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/08/01/61208.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/61208.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/08/01/61208.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/61208.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/61208.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一.spring+struts1.加载springContext      通过struts-config.xml中增加plug-in插件来加载springContext				   &lt;plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;     &lt;set-property proper...&nbsp;&nbsp;<a href='http://www.blogjava.net/rendong/archive/2006/08/01/61208.html'>阅读全文</a><img src ="http://www.blogjava.net/rendong/aggbug/61208.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-08-01 15:06 <a href="http://www.blogjava.net/rendong/archive/2006/08/01/61208.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>结合struts和hibernate谈J2EE架构的数据表示[转载]</title><link>http://www.blogjava.net/rendong/archive/2006/08/01/61185.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Tue, 01 Aug 2006 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/08/01/61185.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/61185.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/08/01/61185.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/61185.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/61185.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<span class="postbody">在 struts+ hibernate 这种结构中，是不应该把Hibernate产生的PO直接传递给JSP的，不管他是Iterator，还是List，这是一个设计错误。 <br /><br />我来谈谈在J2EE架构中各层的数据表示方法： <br /><br />Web层的数据表示是FormBean，数据来源于HTML Form POST <br />业务层的数据表示是VO <br />持久层的数据表示是PO，其数据来源于数据库，持久层的数据表示例如CMP <br /><br />在一个规范的J2EE架构中，不同层的数据表示应该被限制在层内，而不应该扩散到其它层，这样可以降低层间的耦合性，提高J2EE架构整体的可维护性和可扩展性。比如说Web层的逻辑进行了修改，那么只需要修改FormBean的结构，而不需要触动业务层和持久层的代码修改。同样滴，当数据库表进行了小的调整，那么也只需要修改持久层数据表示，而不需要触动业务层代码和Web层代码。 <br /><br />不过由于Hibernate的强大功能，例如动态生成PO，PO的状态管理可以脱离Session，使得在应用了Hibernate的J2EE框架中，PO完全可以充当VO，因此我们下面把PO和VO合并，统称为PO。 <br /><br />先来谈谈ActionFormBean和持久层的PO之间的重大区别。 <br /><br />在简单的应用中，ActionFormBean和PO几乎是没有区别，所以很多人干脆就是用ActionFormBean来充当PO，于是ActionFormBean从JSP页面到Servlet控制层再到业务层，然后穿过持久层，最后一直映射到数据库表。真是一竿子捅到了底！ <br /><br />但是在复杂的应用中，ActionFormBean和PO是分离的，他们也不可能一样。ActionFormBean是和网页里面的Form表单一一对应的，Form里面有什么元素，Bean里面就有什么属性。而PO和数据库表对应，因此如果数据库表不修改，那么PO也不会修改，如果页面的流程和数据库表字段对应关系不一致，那么你又如何能够使用ActionFormBean来取代PO呢？ <br /><br />比如说吧，用户注册页面要求注册用户的基本信息，因此HTML Form里面包含了基本信息属性，于是你需要一个ActionFormBean来一一对应(注意：是一一对应)，每个Bean属性对应一个文本框或者选择框什么的。 <br /><br />而用户这个持久对象呢？他的属性和ActionFormBean有什么明显不同呢？他会有一些ActionFormBean所没有的集合属性，比如说用户的权限属性，用户的组属性，用户的帖子等等。另外还有可能的是在ActionFormBean里面有3个属性，分别是用户的First Name, Middle Name, Last Name，而在我的User这个持久对象中就是一个 Name 对象属性。 <br /><br />假设我的注册页面原来只要你提供First Name，那么ActionFormBean就这一个属性，后来我要你提供全名，你要改ActionFormBean，加两个属性。但是这个时候PO是不应该修改滴，因为数据库没有改。 <br /><br />那么在一个完整的J2EE系统中应该如何进行合理的设计呢？ <br /><br />JSP(View) ---&gt; ActionFormBean(Module) ---&gt; Action(Control) <br /><br />ActionFormBean是Web层的数据表示，它和HTML页面Form对应，只要Web页面的操作流程发生改变，它就要相应的进行修改，它不应该也不能被传递到业务层和持久层，否则一旦页面修改，会一直牵连到业务层和持久层的大面积的代码进行修改，对于软件的可维护性和可扩展性而言，是一个灾难，Actiont就是他的边界，到此为止！ <br /><br />Action(Web Control) ---&gt; Business Bean ---&gt; DAO ---&gt; ORM ---&gt;DB <br /><br />而PO则是业务层和持久层的数据表示，它在业务层和持久层之间进行流动，他不应该也不能被传递到Web层的View中去，而ActionServlet就是他的边界，到此为止！ <br /><br />然后来看一看整个架构的流程： <br /><br />当用户通过浏览器访问网页，提交了一个页面。于是Action拿到了这个FormBean，他会把FormBean属性读出来，然后构造一个PO对象，再调用业务层的Bean类，完成了注册操作，重定向到成功页面。而业务层Bean收到这个PO对象之后，调用DAO接口方法，进行持久对象的持久化操作。 <br /><br />当用户查询某个会员的信息的时候，他用全名进行查询，于是Action得到一个UserNameFormBean包括了3个属性，分别是first name, middle name, last name，然后Action把UserNameFormBean的3个属性读出来，构造Name对象，再调用业务Bean，把Name对象传递给业务Bean，进行查询。 <br /><br />业务Bean取得Name(注意: Name对象只是User的一个属性)对象之后调用DAO接口，返回一个User的PO对象，注意这个User不同于在Web层使用的UserFormBean，他有很多集合属性滴。然后业务Bean把User对象返回给Action。 <br /><br />Action拿到User之后，把User的基本属性取出(集合属性如果不需要就免了)，构造UserFormBean，然后把UserFormBean request.setAttribute(...)，然后重定向到查询结果页面。 <br /><br />查询页面拿到request对象里面的ActionFormBean，自动调用tag显示之。 <br /><br />总结： <br /><br />FormBean是Web层的数据表示，他不能被传递到业务层；PO是持久层的数据表示，在特定情况下，例如Hibernate中，他可以取代VO出现在业务层，但是不管PO还是VO都必须限制在业务层内使用，最多到达Web层的Control，绝不能被扩散到View去。 <br /><br />FormBean和PO之间的数据转化是在Action中进行滴。 <br /><br />BTW: <br /><br />JDO1.x还不能像Hibernate功能这样强大，PO不能脱离持久层，所以必须在业务层使用VO，因此必须在业务层进行大量的VO和PO的转化操作，相对于Hibernate来说，编程比较烦琐。 <br /><br />当然咯，理论是一回事，实际操作也不一定非要这样干，你可以自行取舍，在实际项目中灵活一点，增加一点bad smell，提高开发效率。只不过在大型项目中最好还是严丝合缝，不然的话，改版的时候会痛苦的很滴。</span>
				<b>
						<br />
				</b>
		</div>
<img src ="http://www.blogjava.net/rendong/aggbug/61185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-08-01 13:49 <a href="http://www.blogjava.net/rendong/archive/2006/08/01/61185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts+Spring+Hibernate实现上传下载(转载自http://www.blogjava.net/ltc603/archive/2006/01/13/27966.html)</title><link>http://www.blogjava.net/rendong/archive/2006/07/31/60977.html</link><dc:creator>rendong</dc:creator><author>rendong</author><pubDate>Mon, 31 Jul 2006 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/rendong/archive/2006/07/31/60977.html</guid><wfw:comment>http://www.blogjava.net/rendong/comments/60977.html</wfw:comment><comments>http://www.blogjava.net/rendong/archive/2006/07/31/60977.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rendong/comments/commentRss/60977.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rendong/services/trackbacks/60977.html</trackback:ping><description><![CDATA[
		<p>
				<strong>(转载自<a href="/ltc603/archive/2006/01/13/27966.html">http://www.blogjava.net/ltc603/archive/2006/01/13/27966.html</a>)<br />引言<br /><br /></strong>　　文件的上传和下载在J2EE编程已经是一个非常古老的话题了，也许您马上就能掰着指头数出好几个著名的大件：如SmartUpload、Apache的FileUpload。但如果您的项目是构建在Struts+Spring+Hibernate（以下称SSH）框架上的，这些大件就显得笨重而沧桑了，SSH提供了一个简捷方便的文件上传下载的方案，我们只需要通过一些配置并辅以少量的代码就可以完好解决这个问题了。<br /><br />　　本文将围绕SSH文件上传下载的主题，向您详细讲述如何开发基于SSH的Web程序。SSH各框架的均为当前最新版本：<br /><br />　　·Struts 1.2<br /><br />　　·Spring 1.2.5<br /><br />　　·Hibernate 3.0<br /><br />　　本文选用的数据库为Oracle 9i，当然你可以在不改动代码的情况下，通过配置文件的调整将其移植到任何具有Blob字段类型的数据库上，如MySQL，SQLServer等。<br /><br />　　<b>总体实现</b><br /><br />　　上传文件保存到T_FILE表中，T_FILE表结构如下：<br /><br /></p>
		<table width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<div align="center">
												<img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095916710.gif" border="0" />
												<br />图 1 T_FILE表结构</div>
								</td>
						</tr>
				</tbody>
		</table>
		<br />　　其中：<br /><br />　　·FILE_ID：文件ID，32个字符，用Hibernate的uuid.hex算法生成。<br /><br />　　·FILE_NAME：文件名。<br /><br />　　·FILE_CONTENT：文件内容，对应Oracle的Blob类型。<br /><br />　　·REMARK：文件备注。<br /><br />　　文件数据存储在Blob类型的FILE_CONTENT表字段上，在Spring中采用OracleLobHandler来处理Lob字段（包括Clob和Blob），由于在程序中不需要引用到oracle数据驱动程序的具体类且屏蔽了不同数据库处理Lob字段方法上的差别，从而撤除程序在多数据库移植上的樊篱。 <br /><br />　　1．首先数据表中的Blob字段在Java领域对象中声明为byte[]类型，而非java.sql.Blob类型。<br /><br />　　2．数据表Blob字段在Hibernate持久化映射文件中的type为org.springframework.orm.hibernate3.support.BlobByteArrayType，即Spring所提供的用户自定义的类型，而非java.sql.Blob。 <br /><br />　　3．在Spring中使用org.springframework.jdbc.support.lob.OracleLobHandler处理Oracle数据库的Blob类型字段。<br /><br />　　通过这样的设置和配置，我们就可以象持久化表的一般字段类型一样处理Blob字段了。<br /><br />　　以上是Spring＋Hibernate将文件二进制数据持久化到数据库的解决方案，而Struts通过将表单中file类型的组件映射为ActionForm中类型为org.apache.struts.upload. FormFile的属性来获取表单提交的文件数据。<br /><br />　　综上所述，我们可以通过图 2，描绘出SSH处理文件上传的方案：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095916406.jpg" border="0" /><br />图 2 SSH处理文件上传技术方案</div></td></tr></tbody></table><br />　　文件上传的页面如图 3所示：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095917560.jpg" border="0" /><br />图 3 文件上传页面</div></td></tr></tbody></table><br />　　文件下载的页面如图 4所示：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095919264.jpg" border="0" /><br />图 4 文件下载页面</div></td></tr></tbody></table><br />　　该工程的资源结构如图 5所示：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095919770.gif" border="0" /><br />图 5 工程资源结构</div></td></tr></tbody></table><br />　　工程的类按SSH的层次结构划分为数据持久层、业务层和Web层；WEB-INF下的applicationContext.xml为Spring的配置文件，struts-config.xml为Struts的配置文件，file-upload.jsp为文件上传页面，file-list.jsp为文件列表页面。<br /><br />　　本文后面的章节将从数据持久层-＞业务层-＞Web层的开发顺序，逐层讲解文件上传下载的开发过程。<br /><br />　　<b>数据持久层</b><br /><br />　　1、领域对象及映射文件<br /><br />　　您可以使用Hibernate Middlegen、HIbernate Tools、Hibernate Syhchronizer等工具或手工的方式，编写Hibernate的领域对象和映射文件。其中对应T_FILE表的领域对象Tfile.java为：<br /><br />　　代码 1 领域对象Tfile<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. package sshfile.model;<br />2. public class Tfile<br />3.{<br />4. private String fileId;<br />5. private String fileName;<br />6. private byte[] fileContent;<br />7. private String remark;<br />8. …//getter and setter<br />9. }</td></tr></tbody></table><br />　　特别需要注意的是：数据库表为Blob类型的字段在Tfile中的fileContent类型为byte[]。Tfile的Hibernate映射文件Tfile.hbm.xml放在Tfile .java类文件的相同目录下：<br /><br />　　代码 2 领域对象映射文件<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜?xml version="1.0"?＞<br />2. ＜!DOCTYPE hibernate-mapping PUBLIC<br />3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"<br />4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" ＞<br />5. ＜hibernate-mapping＞<br />6. ＜class name="sshfile.model.Tfile" table="T_FILE"＞<br />7. ＜id name="fileId" type="java.lang.String" column="FILE_ID"＞<br />8. ＜generator class="uuid.hex"/＞<br />9. ＜/id＞<br />10. ＜property name="fileContent"<br />11. type="org.springframework.orm.hibernate3.support.BlobByteArrayType"<br />12. column="FILE_CONTENT" lazy="true"/＞<br />13. …//其它一般字段的映射<br />14. ＜/class＞<br />15. ＜/hibernate-mapping＞</td></tr></tbody></table><br />　　fileContent字段映射为Spring所提供的BlobByteArrayType类型，BlobByteArrayType是用户自定义的数据类型，它实现了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取的Lob操作句柄lobHandler将byte[]的数据保存到Blob数据库字段中。这样，我们就再没有必要通过硬编码的方式，先insert然后再update来完成Blob类型数据的持久化，这个原来难伺候的老爷终于被平民化了。关于lobHandler的配置请见本文后面的内容。<br /><br />　　此外lazy="true"说明地返回整个Tfile对象时，并不返回fileContent这个字段的数据，只有在显式调用tfile.getFileContent()方法时才真正从数据库中获取fileContent的数据。这是Hibernate3引入的新特性，对于包含重量级大数据的表字段，这种抽取方式提高了对大字段操作的灵活性，否则加载Tfile对象的结果集时如果总是返回fileContent，这种批量的数据抽取将可以引起数据库的"洪泛效应"。<br /><br />　　2、DAO编写和配置<br /><br />　　Spring强调面向接口编程，所以我们将所有对Tfile的数据操作的方法定义在TfileDAO接口中，这些接口方法分别是：<br /><br />　　·findByFildId(String fileId)<br /><br />　　·save(Tfile tfile)<br /><br />　　·List findAll()<br /><br />　　TfileDAOHibernate提供了对TfileDAO接口基于Hibernate的实现，如代码 3所示：<br /><br />　　代码 3 基于Hibernate 的fileDAO实现类<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. package sshfile.dao;<br />2.<br />3. import sshfile.model.*;<br />4. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;<br />5. import java.util.List;<br />6.<br />7. public class TfileDAOHibernate<br />8. extends HibernateDaoSupport implements TfileDAO<br />9. {<br />10. public Tfile findByFildId(String fileId)<br />11. {<br />12. return (Tfile) getHibernateTemplate().get(Tfile.class, fileId);<br />13. }<br />14. public void save(Tfile tfile)<br />15. {<br />16. getHibernateTemplate().save(tfile);<br />17. getHibernateTemplate().flush();<br />18. }<br />19. public List findAll()<br />20. {<br />21. return getHibernateTemplate().loadAll(Tfile.class);<br />22. }<br />23. }</td></tr></tbody></table><br />　　TfileDAOHibernate通过扩展Spring提供的Hibernate支持类HibernateDaoSupport而建立，HibernateDaoSupport封装了HibernateTemplate，而HibernateTemplate封装了Hibernate所提供几乎所有的的数据操作方法，如execute(HibernateCallback action)，load(Class entityClass, Serializable id)，save(final Object entity)等等。<br /><br />　　所以我们的DAO只需要简单地调用父类的HibernateTemplate就可以完成几乎所有的数据库操作了。<br /><br />　　由于Spring通过代理Hibernate完成数据层的操作，所以原Hibernate的配置文件hibernate.cfg.xml的信息也转移到Spring的配置文件中：<br /><br />　　代码 4 Spring中有关Hibernate的配置信息<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜beans＞<br />2. ＜!-- 数据源的配置 //--＞<br />3. ＜bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"<br />4. destroy-method="close"＞<br />5. ＜property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/＞<br />6. ＜property name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/＞<br />7. ＜property name="username" value="test"/＞<br />8. ＜property name="password" value="test"/＞<br />9. ＜/bean＞<br />10. ＜!-- Hibernate会话工厂配置 //--＞<br />11. ＜bean id="sessionFactory"<br />12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"＞<br />13. ＜property name="dataSource" ref="dataSource"/＞<br />14. ＜property name="mappingDirectoryLocations"＞<br />15. ＜list＞<br />16. ＜value＞classpath:/sshfile/model＜/value＞<br />17. ＜/list＞<br />18. ＜/property＞<br />19. ＜property name="hibernateProperties"＞<br />20. ＜props＞<br />21. ＜prop key="hibernate.dialect"＞org.hibernate.dialect.OracleDialect＜/prop＞<br />22. ＜prop key="hibernate.cglib.use_reflection_optimizer"＞true＜/prop＞<br />23. ＜/props＞<br />24. ＜/property＞<br />25. ＜/bean＞<br />26. ＜!-- Hibernate 模板//--＞<br />27. ＜bean id="hibernateTemplate"<br />28. class="org.springframework.orm.hibernate3.HibernateTemplate"＞<br />29. ＜property name="sessionFactory" ref="sessionFactory"/＞<br />30. ＜/bean＞<br />31. ＜!--DAO配置 //--＞<br />32. ＜bean id="tfileDAO" class="sshfile.dao.TfileDAOHibernate"＞<br />33. ＜property name="hibernateTemplate" ref="hibernateTemplate" /＞<br />34. ＜/bean＞<br />35. …<br />36. ＜/beans＞</td></tr></tbody></table><br />　　第3~9行定义了一个数据源，其实现类是apache的BasicDataSource，第11~25行定义了Hibernate的会话工厂，会话工厂类用Spring提供的LocalSessionFactoryBean维护，它注入了数据源和资源映射文件，此外还通过一些键值对设置了Hibernate所需的属性。<br /><br />　　其中第16行通过类路径的映射方式，将sshfile.model类包目录下的所有领域对象的映射文件装载进来，在本文的例子里，它将装载进Tfile.hbm.xml映射文件。如果有多个映射文件需要声明，使用类路径映射方式显然比直接单独指定映射文件名的方式要简便。 <br /><br />　　第27~30行定义了Spring代理Hibernate数据操作的HibernateTemplate模板，而第32~34行将该模板注入到tfileDAO中。<br /><br />　　需要指定的是Spring 1.2.5提供了两套Hibernate的支持包，其中Hibernate 2相关的封装类位于org.springframework.orm.hibernate2.*包中，而Hibernate 3.0的封装类位于org.springframework.orm.hibernate3.*包中，需要根据您所选用Hibernate版本进行正确选择。<br /><br />　　3、Lob字段处理的配置<br /><br />　　我们前面已经指出Oracle的Lob字段和一般类型的字段在操作上有一个明显的区别--那就是你必须首先通过Oracle的empty_blob()/empty_clob()初始化Lob字段，然后获取该字段的引用，通过这个引用更改其值。所以要完成对Lob字段的操作，Hibernate必须执行两步数据库访问操作，先Insert再Update。<br /><br />　　使用BlobByteArrayType字段类型后，为什么我们就可以象一般的字段类型一样操作Blob字段呢？可以确定的一点是：BlobByteArrayType不可能逾越Blob天生的操作方式，原来是BlobByteArrayType数据类型本身具体数据访问的功能，它通过LobHandler将两次数据访问的动作隐藏起来，使Blob字段的操作在表现上和其他一般字段业类型无异，所以LobHandler即是那个"苦了我一个，幸福十亿人"的那位幕后英雄。<br /><br />　　LobHandler必须注入到Hibernate会话工厂sessionFactory中，因为sessionFactory负责产生与数据库交互的Session。LobHandler的配置如代码 5所示：<br /><br />　　代码 5 Lob字段的处理句柄配置<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜beans＞<br />2. …<br />3. ＜bean id="nativeJdbcExtractor"<br />4. class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"<br />5. lazy-init="true"/＞<br />6. ＜bean id="lobHandler"<br />7. class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true"＞<br />8. ＜property name="nativeJdbcExtractor"＞<br />9. ＜ref local="nativeJdbcExtractor"/＞<br />10. ＜/property＞<br />11. ＜/bean＞<br />12. …<br />13. ＜/beans＞</td></tr></tbody></table><br />　　首先，必须定义一个能够从连接池中抽取出本地数据库JDBC对象（如OracleConnection，OracleResultSet等）的抽取器：nativeJdbcExtractor，这样才可以执行一些特定数据库的操作。对于那些仅封装了Connection而未包括Statement的简单数据连接池，SimpleNativeJdbcExtractor是效率最高的抽取器实现类，但具体到apache的BasicDataSource连接池，它封装了所有JDBC的对象，这时就需要使用CommonsDbcpNativeJdbcExtractor了。Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器：<br /><br />　　·WebLogic：WebLogicNativeJdbcExtractor<br /><br />　　·WebSphere：WebSphereNativeJdbcExtractor<br /><br />　　·JBoss：JBossNativeJdbcExtractor<br /><br />　　在定义了JDBC抽取器后，再定义lobHandler。Spring 1.2.5提供了两个lobHandler：<br /><br />　　·DefaultLobHandler：适用于大部分的数据库，如SqlServer，MySQL，对Oracle 10g也适用，但不适用于Oracle 9i（看来Oracle 9i确实是个怪胎，谁叫Oracle 公司自己都说Oracle 9i是一个过渡性的产品呢）。<br /><br />　　·OracleLobHandler：适用于Oracle 9i和Oracle 10g。<br /><br />　　由于我们的数据库是Oracle9i，所以使用OracleLobHandler。<br /><br />　　在配置完LobHandler后， 还需要将其注入到sessionFactory的Bean中，下面是调用后的sessionFactory Bean的配置：<br /><br />　　代码 6 将lobHandler注入到sessionFactory中的配置<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜beans＞<br />2. …<br />3. ＜bean id="sessionFactory"<br />4. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"＞<br />5. ＜property name="dataSource" ref="dataSource"/＞<br />6. ＜!-- 为处理Blob类型字段的句柄声明 //--＞<br />7. ＜property name="lobHandler" ref="lobHandler"/＞<br />8. …<br />9. ＜/bean＞<br />10. …<br />11. ＜/beans＞</td></tr></tbody></table><br />　　如第7所示，通过sessionFactory的lobHandler属性进行注入。<br /><br />　　<b>业务层</b><br /><br />　　1、业务层接口<br /><br />　　"面向接口而非面向类编程"是Spring不遗余力所推荐的编程原则，这条原则也已经为大部开发者所接受；此外，JDK的动态代理只对接口有效，否则必须使用CGLIB生成目标类的子类。我们依从于Spring的倡导为业务类定义一个接口：<br /><br />　　代码 7 业务层操作接口<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. public interface FileService<br />2. {<br />3. void save(FileActionForm fileForm);//将提交的上传文件保存到数据表中<br />4. List getAllFile();//得到T_FILE所示记录<br />5. void write(OutputStream os,String fileId);//将某个文件的文件数据写出到输出流中<br />6. String getFileName(String fileId);//获取文件名<br />7. }</td></tr></tbody></table><br />　　其中save(FileActionForm fileForm)方法，将封装在fileForm中的上传文件保存到数据库中，这里我们使用FileActionForm作为方法入参，FileActionForm是Web层的表单数据对象，它封装了提交表单的数据。将FileActionForm直接作为业务层的接口入参，相当于将Web层传播到业务层中去，即将业务层绑定在特定的Web层实现技术中，按照分层模型学院派的观点，这是一种反模块化的设计，但在"一般"的业务系统并无需提供多种UI界面，系统Web层将来切换到另一种实现技术的可能性也微乎其微，所以笔者觉得没有必要为了这个业务层完全独立于调用层的过高目标而去搞一个额外的隔离层，浪费了原材料不说，还将系统搞得过于复杂，相比于其它原则，"简单"始终是最大的一条原则。<br /><br />　　getAllFile()负责获取T_FILE表所有记录，以便在网页上显示出来。<br /><br />　　而getFileName(String fileId)和write(OutputStream os,String fileId)则用于下载某个特定的文件。具体的调用是将Web层将response.getOutputStream()传给write(OutputStream os,String fileId)接口，业务层直接将文件数据输出到这个响应流中。具体实现请参见错误！未找到引用源。节下载文件部分。<br /><br />　　2、业务层接口实现类<br /><br />　　FileService的实现类为FileServiceImpl，其中save(FileActionForm fileForm)的实现如下所示：<br /><br />　　代码 8 业务接口实现类之save()<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. …<br />2. public class FileServiceImpl<br />3. implements FileService<br />4. {<br />5. private TfileDAO tfileDAO;<br />6. public void save(FileActionForm fileForm)<br />7. {<br />8. Tfile tfile = new Tfile();<br />9. try<br />10. {<br />11. tfile.setFileContent(fileForm.getFileContent().getFileData());<br />12. }<br />13. catch (FileNotFoundException ex)<br />14. {<br />15. throw new RuntimeException(ex);<br />16. }<br />17. catch (IOException ex)<br />18. {<br />19. throw new RuntimeException(ex);<br />20. }<br />21. tfile.setFileName(fileForm.getFileContent().getFileName());<br />22. tfile.setRemark(fileForm.getRemark());<br />23. tfileDAO.save(tfile);<br />24. }<br />25. …<br />26. }</td></tr></tbody></table><br />　　在save(FileActionForm fileForm)方法里，完成两个步骤：<br /><br />　　其一，象在水桶间倒水一样，将FileActionForm对象中的数据倒入到Tfile对象中；<br /><br />　　其二，调用TfileDAO保存数据。<br /><br />　　需要特别注意的是代码的第11行，FileActionForm的fileContent属性为org.apache.struts.upload.FormFile类型，FormFile提供了一个方便的方法getFileData()，即可获取文件的二进制数据。通过解读FormFile接口实现类DiskFile的原码，我们可能知道FormFile本身并不缓存文件的数据，只有实际调用getFileData()时，才从磁盘文件输入流中获取数据。由于FormFile使用流读取方式获取数据，本身没有缓存文件的所有数据，所以对于上传超大体积的文件，也是没有问题的；但是，由于数据持久层的Tfile使用byte[]来缓存文件的数据，所以并不适合处理超大体积的文件（如100M），对于超大体积的文件，依然需要使用java.sql.Blob类型以常规流操作的方式来处理。<br /><br />　　此外，通过FileForm的getFileName()方法就可以获得上传文件的文件名，如第21行代码所示。<br /><br />　　write(OutputStream os,String fileId)方法的实现，如代码 9所示：<br /><br />　　代码 9 业务接口实现类之write()<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. …<br />2. public class FileServiceImpl<br />3. implements FileService<br />4. {<br />5.<br />6. public void write(OutputStream os, String fileId)<br />7. {<br />8. Tfile tfile = tfileDAO.findByFildId(fileId);<br />9. try<br />10. {<br />11. os.write(tfile.getFileContent());<br />12. os.flush();<br />13. }<br />14. catch (IOException ex)<br />15. {<br />16. throw new RuntimeException(ex);<br />17. }<br />18. }<br />19. …<br />20. }</td></tr></tbody></table><br />　　write(OutputStream os,String fileId)也简单地分为两个操作步骤，首先，根据fileId加载表记录，然后将fileContent写入到输出流中。<br /><br />　　3、Spring事务配置<br /><br />　　下面，我们来看如何在Spring配置文件中为FileService配置声明性的事务<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜beans＞<br />2. … <br />3. ＜bean id="transactionManager"<br />4. class="org.springframework.orm.hibernate3.HibernateTransactionManager"＞<br />5. ＜property name="sessionFactory" ref="sessionFactory"/＞<br />6. ＜/bean＞<br />7. ＜!-- 事务处理的AOP配置 //--＞<br />8. ＜bean id="txProxyTemplate" abstract="true"<br />9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"＞<br />10. ＜property name="transactionManager" ref="transactionManager"/＞<br />11. ＜property name="transactionAttributes"＞<br />12. ＜props＞<br />13. ＜prop key="get*"＞PROPAGATION_REQUIRED,readOnly＜/prop＞<br />14. ＜prop key="find*"＞PROPAGATION_REQUIRED,readOnly＜/prop＞<br />15. ＜prop key="save"＞PROPAGATION_REQUIRED＜/prop＞<br />16. ＜prop key="write"＞PROPAGATION_REQUIRED,readOnly＜/prop＞<br />17. ＜/props＞<br />18. ＜/property＞<br />19. ＜/bean＞<br />20. ＜bean id="fileService" parent="txProxyTemplate"＞<br />21. ＜property name="target"＞<br />22. ＜bean class="sshfile.service.FileServiceImpl"＞<br />23. ＜property name="tfileDAO" ref="tfileDAO"/＞<br />24. ＜/bean＞<br />25. ＜/property＞<br />26. ＜/bean＞<br />27. ＜/beans＞</td></tr></tbody></table><br />　　Spring的事务配置包括两个部分：<br /><br />　　其一，定义事务管理器transactionManager，使用HibernateTransactionManager实现事务管理；<br /><br />　　其二，对各个业务接口进行定义，其实txProxyTemplate和fileService是父子节点的关系，本来可以将txProxyTemplate定义的内容合并到fileService中一起定义，由于我们的系统仅有一个业务接口需要定义，所以将其定义的一部分抽象到父节点txProxyTemplate中意义确实不大，但是对于真实的系统，往往拥有为数众多的业务接口需要定义，将这些业务接口定义内容的共同部分抽取到一个父节点中，然后在子节点中通过parent进行关联，就可以大大简化业务接口的配置了。<br /><br />　　父节点txProxyTemplate注入了事务管理器，此外还定义了业务接口事务管理的方法（允许通过通配符的方式进行匹配声明，如前两个接口方法），有些接口方法仅对数据进行读操作，而另一些接口方法需要涉及到数据的更改。对于前者，可以通过readOnly标识出来，这样有利于操作性能的提高，需要注意的是由于父类节点定义的Bean仅是子节点配置信息的抽象，并不能具体实现化一个Bean对象，所以需要特别标注为abstract="true"，如第8行所示。<br /><br />　　fileService作为一个目标类被注入到事务代理器中，而fileService实现类所需要的tfileDAO实例，通过引用3.2节中定义的tfileDAO Bean注入。<br /><br />　　<b>Web层实现</b><br /><br />　　1、Web层的构件和交互流程<br /><br />　　Web层包括主要3个功能：<br /><br />　　·上传文件。<br /><br />　　·列出所有已经上传的文件列表，以供点击下载。<br /><br />　　·下载文件。<br /><br />　　Web层实现构件包括与2个JSP页面，1个ActionForm及一个Action：<br /><br />　　·file-upload.jsp：上传文件的页面。<br /><br />　　·file-list.jsp：已经上传文件的列表页面。<br /><br />　　·FileActionForm：file-upload.jsp页面表单对应的ActionForm。<br /><br />　　·FileAction：继承org.apache.struts.actions.DispatchAction的Action，这样这个Action就可以通过一个URL参数区分中响应不同的请求。<br /><br />　　Web层的这些构件的交互流程如图 6所示：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095919215.jpg" border="0" /><br />图 6 Web层Struts流程图</div></td></tr></tbody></table><br />　　其中，在执行文件上传的请求时，FileAction在执行文件上传后，forward到loadAllFile出口中，loadAllFile加载数据库中所有已经上传的记录，然后forward到名为fileListPage的出口中，调用file-list.jsp页面显示已经上传的记录。<br /><br />　　2、FileAction功能<br /><br />　　Struts 1.0的Action有一个弱项：一个Action只能处理一种请求，Struts 1.1中引入了一个DispatchAction，允许通过URL参数指定调用Action中的某个方法，如http://yourwebsite/fileAction.do?method=upload即调用FileAction中的upload方法。通过这种方式，我们就可以将一些相关的请求集中到一个Action当中编写，而没有必要为某个请求操作编写一个Action类。但是参数名是要在struts-config.xml中配置的：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜struts-config＞<br />2. ＜form-beans＞<br />3. ＜form-bean name="fileActionForm" type="sshfile.web.FileActionForm" /＞<br />4. ＜/form-beans＞<br />5. ＜action-mappings＞<br />6. ＜action name="fileActionForm" parameter="method" path="/fileAction"<br />7. type="sshfile.web.FileAction"＞<br />8. ＜forward name="fileListPage" path="/file-list.jsp" /＞<br />9. ＜forward name="loadAllFile" path="/fileAction.do?method=listAllFile" /＞<br />10. ＜/action＞<br />11. ＜/action-mappings＞<br />12. ＜/struts-config＞</td></tr></tbody></table><br />　　第6行的parameter="method"指定了承载方法名的参数，第9行中，我们还配置了一个调用FileAction不同方法的Action出口。<br /><br />　　FileAction共有3个请求响应的方法，它们分别是：<br /><br />　　·upload(…)：处理上传文件的请求。<br /><br />　　·listAllFile(…)：处理加载数据库表中所有记录的请求。<br /><br />　　·download（…）：处理下载文件的请求。<br /><br />　　下面我们分别对这3个请求处理方法进行讲解。<br /><br />　　2.1 上传文件<br /><br />　　上传文件的请求处理方法非常简单，简之言之，就是从Spring容器中获取业务层处理类FileService，调用其save(FileActionForm form)方法上传文件，如下所示：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. public class FileAction<br />2. extends DispatchAction<br />3. {<br />4. //将上传文件保存到数据库中<br />5. public ActionForward upload(ActionMapping mapping, ActionForm form,<br />6. HttpServletRequest request,<br />7. HttpServletResponse response)<br />8. {<br />9. FileActionForm fileForm = (FileActionForm) form;<br />10. FileService fileService = getFileService();<br />11. fileService.save(fileForm);<br />12. return mapping.findForward("loadAllFile");<br />13. }<br />14. //从Spring容器中获取FileService对象<br />15. private FileService getFileService()<br />16. {<br />17. ApplicationContext appContext = WebApplicationContextUtils.<br />18. getWebApplicationContext(this.getServlet().getServletContext());<br />19. return (FileService) appContext.getBean("fileService");<br />20. }<br />21. …<br />22. }</td></tr></tbody></table><br />　　由于FileAction其它两个请求处理方法也需要从Spring容器中获取FileService实例，所以我们特别提供了一个getFileService()方法（第15~21行）。重构的一条原则就是："发现代码中有重复的表达式，将其提取为一个变量；发现类中有重复的代码段，将其提取为一个方法；发现不同类中有相同的方法，将其提取为一个类"。在真实的系统中，往往拥有多个Action和多个Service类，这时一个比较好的设置思路是，提供一个获取所有Service实现对象的工具类，这样就可以将Spring 的Service配置信息屏蔽在一个类中，否则Service的配置名字散落在程序各处，维护性是很差的。<br /><br />　　2.2 列出所有已经上传的文件<br /><br />　　listAllFile方法调用Servie层方法加载T_FILE表中所有记录，并将其保存在Request域中，然后forward到列表页面中：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. public class FileAction<br />2. extends DispatchAction<br />3. {<br />4. …<br />5. public ActionForward listAllFile(ActionMapping mapping, ActionForm form,<br />6. HttpServletRequest request,<br />7. HttpServletResponse response)<br />8. throws ModuleException<br />9. {<br />10. FileService fileService = getFileService();<br />11. List fileList = fileService.getAllFile();<br />12. request.setAttribute("fileList",fileList);<br />13. return mapping.findForward("fileListPage");<br />14. }<br />15. }</td></tr></tbody></table><br />　　file-list.jsp页面使用Struts标签展示出保存在Request域中的记录：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜%@page contentType="text/html; charset=GBK"%＞<br />2. ＜%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%＞<br />3. ＜%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%＞<br />4. ＜html＞<br />5. ＜head＞<br />6. ＜title＞file-download＜/title＞<br />7. ＜/head＞<br />8. ＜body bgcolor="#ffffff"＞<br />9. ＜ol＞<br />10. ＜logic:iterate id="item" name="fileList" scope="request"＞<br />11. ＜li＞<br />12. ＜a href='fileAction.do?method=download&amp;fileId=<br />13. ＜bean:write name="item"property="fileId"/＞'＞<br />14. ＜bean:write name="item" property="fileName"/＞<br />15. ＜/a＞<br />16. ＜/li＞<br />17. ＜/logic:iterate＞<br />18. ＜/ol＞<br />19. ＜/body＞<br />20. ＜/html＞</td></tr></tbody></table><br />　　展现页面的每条记录挂接着一个链接地址，形如：fileAction.do?method=download&amp;fileId=xxx，method参数指定了这个请求由FileAction的download方法来响应，fileId指定了记录的主键。<br /><br />　　由于在FileActionForm中，我们定义了fileId的属性，所以在download响应方法中，我们将可以从FileActionForm中取得fileId的值。这里涉及到一个处理多个请求Action所对应的ActionForm的设计问题，由于原来的Action只能对应一个请求，那么原来的ActionForm非常简单，它仅需要将这个请求的参数项作为其属性就可以了，但现在一个Action对应多个请求，每个请求所对应的参数项是不一样的，此时的ActionForm的属性就必须是多请求参数项的并集了。所以，除了文件上传请求所对应的fileContent和remark属性外还包括文件下载的fileId属性：<br /><br /><table width="90%" align="center" border="0"><tbody><tr><td><div align="center"><img src="http://java.chinaitlab.com/UploadFiles_8734/200512/20051223095919511.jpg" border="0" /><br />图 7 FileActionForm</div></td></tr></tbody></table><br />　　当然这样会造成属性的冗余，比如在文件上传的请求中，只会用到fileContent和remark属性，而在文件下载的请求时，只会使用到fileId属性。但这种冗余是会带来好处的--它使得一个Action可以处理多个请求。<br /><br />　　2.3 下载文件<br /><br />　　在列表页面中点击一个文件下载，其请求由FileAction的download方法来响应，download方法调用业务层的FileService方法，获取文件数据并写出到response的响应流中。通过合理设置HTTP响应头参数，将响应流在客户端表现为一个下载文件对话框，其代码如下所示：<br /><br />　　代码 10 业务接口实现类之download<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. public class FileAction<br />2. extends DispatchAction<br />3. {<br />4. …<br />5. public ActionForward download(ActionMapping mapping, ActionForm form,<br />6. HttpServletRequest request,<br />7. HttpServletResponse response)<br />8. throws ModuleException<br />9. {<br />10. FileActionForm fileForm = (FileActionForm) form;<br />11. FileService fileService = getFileService();<br />12. String fileName = fileService.getFileName(fileForm.getFileId());<br />13. try<br />14. {<br />15. response.setContentType("application/x-msdownload");<br />16. response.setHeader("Content-Disposition",<br />17. "attachment;" + " filename="+<br />18. new String(fileName.getBytes(), "ISO-8859-1"));<br />19. fileService.write(response.getOutputStream(), fileForm.getFileId());<br />20. }<br />21. catch (Exception e)<br />22. {<br />23. throw new ModuleException(e.getMessage());<br />24. }<br />25. return null;<br />26. }<br />27. }</td></tr></tbody></table><br />　　第15~18行，设置HTTP响应头，将响应类型设置为application/x-msdownload MIME类型，则响应流在IE中将弹出一个文件下载的对话框，如图 4所示。IE所支持的MIME类型多达26种，您可以通过这个网址查看其他的MIME类型：<br /><br />http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp。<br /><br />　　如果下载文件的文件名含有中文字符，如果不对其进行硬编码，如第18行所示，客户文件下载对话框中出现的文件名将会发生乱码。<br />第19行代码获得response的输出流，作为FileServie write(OutputStream os,String fileId)的入参，这样文件的内容将写到response的输出流中。<br /><br />　　3、web.xml文件的配置<br /><br />　　Spring容器在何时启动呢？我可以在Web容器初始化来执行启动Spring容器的操作，Spring提供了两种方式启动的方法：<br /><br />　　·通过org.springframework.web.context .ContextLoaderListener容器监听器，在Web容器初始化时触发初始化Spring容器，在web.xml中通过＜listener＞＜/listener＞对其进行配置。<br /><br />　　·通过Servlet org.springframework.web.context.ContextLoaderServlet，将其配置为自动启动的Servlet，在Web容器初始化时，通过这个Servlet启动Spring容器。<br /><br />　　在初始化Spring容器之前，必须先初始化log4J的引擎，Spring也提供了容器监听器和自动启动Servlet两种方式对log4J引擎进行初始化：<br /><br />　　·org.springframework.web.util .Log4jConfigListener<br /><br />　　·org.springframework.web.util.Log4jConfigServlet<br /><br />　　下面我们来说明如何配置web.xml启动Spring容器：<br /><br />　　代码 11 web.xml中对应Spring的配置内容<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜web-app＞<br />2. ＜context-param＞<br />3. ＜param-name＞contextConfigLocation＜/param-name＞<br />4. ＜param-value＞/WEB-INF/applicationContext.xml＜/param-value＞<br />5. ＜/context-param＞<br />6. ＜context-param＞<br />7. ＜param-name＞log4jConfigLocation＜/param-name＞<br />8. ＜param-value＞/WEB-INF/log4j.properties＜/param-value＞<br />9. ＜/context-param＞<br />10. ＜servlet＞<br />11. ＜servlet-name＞log4jInitServlet＜/servlet-name＞<br />12. ＜servlet-class＞org.springframework.web.util.Log4jConfigServlet＜/servlet-class＞<br />13. ＜load-on-startup＞1＜/load-on-startup＞<br />14. ＜/servlet＞<br />15. ＜servlet＞<br />16. ＜servlet-name＞springInitServlet＜/servlet-name＞<br />17. ＜servlet-class＞org.springframework.web.context.ContextLoaderServlet＜/servlet-class＞<br />18. ＜load-on-startup＞2＜/load-on-startup＞<br />19. ＜/servlet＞<br />20. …<br />21. ＜/web-app＞</td></tr></tbody></table><br />　　启动Spring容器时，需要得到两个信息：Spring配置文件的地址和Log4J属性文件，这两上信息分别通过contextConfigLocationWeb和log4jConfigLocation容器参数指定，如果有多个Spring配置文件，则用逗号隔开，如：<br /><br />/WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2<br /><br />　　由于在启动ContextLoaderServlet之前，必须事先初始化Log4J的引擎，所以Log4jConfigServlet必须在ContextLoaderServlet之前启动，这通过＜load-on-startup＞来指定它们启动的先后顺序。<br /><br />　　乱码是开发Web应用程序一个比较老套又常见问题，由于不同Web应用服务器的默认编码是不一样的，为了方便Web应用在不同的Web应用服务器上移植，最好的做法是Web程序自身来处理编码转换的工作。经典的作法是在web.xml中配置一个编码转换过滤器，Spring就提供了一个编码过滤器类CharacterEncodingFilter，下面，我们为应用配置上这个过滤器：<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>1. ＜web-app＞<br />2. …<br />3. ＜filter＞<br />4. ＜filter-name＞encodingFilter＜/filter-name＞<br />5. ＜filter-class＞org.springframework.web.filter.CharacterEncodingFilter＜/filter-class＞<br />6. ＜init-param＞<br />7. ＜param-name＞encoding＜/param-name＞<br />8. ＜param-value＞GBK＜/param-value＞<br />9. ＜/init-param＞<br />10. ＜/filter＞<br />11. ＜filter-mapping＞<br />12. ＜filter-name＞encodingFilter＜/filter-name＞<br />13. ＜url-pattern＞/*＜/url-pattern＞<br />14. ＜/filter-mapping＞<br />15. …<br />16. ＜/web-app＞</td></tr></tbody></table><br />　　Spring的过滤器类是org.springframework.web.filter.CharacterEncodingFilter，通过encoding参数指定编码转换类型为GBK，＜filter-mapping＞的配置使该过滤器截获所有的请示。<br /><br />　　Struts的框架也需要在web.xml中配置，想必读者朋友对Struts的配置都很熟悉，故在此不再提及，请参见本文所提供的源码。<br /><br />　　<b>总结</b><br /><br />　　本文通过一个文件上传下载的Web应用，讲解了如何构建基于SSH的Web应用，通过Struts和FormFile，Spring的LobHandler以及Spring为HibernateBlob处理所提供的用户类BlobByteArrayType ，实现上传和下载文件的功能仅需要廖廖数行的代码即告完成。读者只需对程序作稍许的调整，即可处理Clob字段：<br /><br />　　·领域对象对应Clob字段的属性声明为String类型；<br /><br />　　·映射文件对应Clob字段的属性声明为org.springframework.orm.hibernate3.support.ClobStringType类型。<br /><br />　　本文通过SSH对文件上传下载简捷完美的实现得以管中窥豹了解SSH强强联合构建Web应用的强大优势。在行文中，还穿插了一些分层的设计经验，配置技巧和Spring所提供的方便类，相信这些知识对您的开发都有所裨益。<img src ="http://www.blogjava.net/rendong/aggbug/60977.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rendong/" target="_blank">rendong</a> 2006-07-31 11:23 <a href="http://www.blogjava.net/rendong/archive/2006/07/31/60977.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>