??xml version="1.0" encoding="utf-8" standalone="yes"?>美腿丝袜亚洲综合,少妇亚洲免费精品,色天使色婷婷在线影院亚洲http://www.tkk7.com/rendong/category/13645.htmlzh-cnThu, 01 Mar 2007 01:13:13 GMTThu, 01 Mar 2007 01:13:13 GMT60Java 中的悲观锁和乐观锁的实现 (转http://www.tkk7.com/liuwentao253/archive/2006/06/20/53934.html)http://www.tkk7.com/rendong/archive/2006/12/27/90326.htmlrendongrendongWed, 27 Dec 2006 08:40:00 GMThttp://www.tkk7.com/rendong/archive/2006/12/27/90326.htmlhttp://www.tkk7.com/rendong/comments/90326.htmlhttp://www.tkk7.com/rendong/archive/2006/12/27/90326.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/90326.htmlhttp://www.tkk7.com/rendong/services/trackbacks/90326.html锁(lockingQ?
业务逻辑的实现过E中Q往往需要保证数据访问的排他性。如在金融系l的日终l算 处理中,我们希望针对某个cut-off旉点的数据q行处理Q而不希望在结进行过E中 Q可能是几秒U,也可能是几个时Q,数据再发生变化。此Ӟ我们需要通过一些机制来保证q些数据在某个操作过E中不会被外界修改,q样的机Ӟ在这里,也就是所?的“锁”,?font color="#0000ff">l我们选定的目标数据上锁,使其无法被其他程序修?/strong>?Hibernate支持两种锁机Ӟ即通常所说的“悲观锁QPessimistic LockingQ?和“乐观锁QOptimistic LockingQ”?/p>


一 Q?font color="#0000ff">悲观?/strong>Q?u>Pessimistic LockingQ?
悲观锁,正如其名Q它指的是对数据被外界(包括本系l当前的其他事务Q以及来自外部系l的事务处理Q修Ҏ保守态度Q因此,在整个数据处理过E中Q将数据处于锁定 状态。悲观锁的实玎ͼ往往依靠数据库提供的锁机Ӟ也只有数据库层提供的锁机制才?真正保证数据讉K的排他?/u>Q否则,即在本pȝ中实C加锁机制Q也无法保证外部p?l不会修Ҏ据)?一个典型的倚赖数据库的悲观锁调用: select * from account where name=”Erica?for update q条sql 语句锁定了account 表中所有符合检索条Ӟname=”Erica”)的记录?本次事务提交之前Q事务提交时会释放事务过E中的锁Q,外界无法修改q些记录?Hibernate的悲观锁Q也是基于数据库的锁机制实现?下面的代码实CҎ询记录的加锁Q?/p>

1 String hqlStr  =   " from TUser as user where user.name=’Erica?/span> "
2 Query query  =  session.createQuery(hqlStr); 
3 query.setLockMode( " user " ,LockMode.UPGRADE);  // 加锁 
4 List userList  =  query.list(); // 执行查询Q?/span>

获取数据 query.setLockMode Ҏ询语句中特定别名所对应的记录进行加锁(我们?TUsercL定了一个别名“user”)Q这里也是对返回的所有user记录q行加锁?观察q行期Hibernate生成的SQL语句Q?/p>

1 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 = ’Erica’?  for  update

 q里Hibernate通过使用数据库的for update子句实现?font color="#0000ff">悲观?/strong>机制?Hibernate的加锁模式有Q?
? LockMode.NONE Q?无锁机制?
? LockMode.WRITE QHibernate在Insert和Update记录的时候会自动 获取?
? LockMode.READ Q?Hibernate在读取记录的时候会自动获取?

以上q三U锁机制一般由Hibernate内部使用Q如HibernateZ保证Update q程中对象不会被外界修改Q会在saveҎ实现中自动ؓ目标对象加上WRITE锁?br /> 
? LockMode.UPGRADE Q?font color="#0000ff">利用数据库的for update子句加锁?
? LockMode. UPGRADE_NOWAIT QOracle的特定实玎ͼ利用Oracle的for update nowait子句实现加锁?

上面q两U锁机制是我们在应用层较为常用的Q加锁一般通过以下Ҏ实现Q?
Criteria.setLockMode
Query.setLockMode
Session.lock
注意Q只有在查询开始之前(也就是Hiberate 生成SQL 之前Q设定加锁,才会 真正通过数据库的锁机制进行加锁处理,否则Q数据已l通过不包含for update 子句的Select SQL加蝲q来Q所谓数据库加锁也就无从谈v?


?Q乐观锁QOptimistic LockingQ?
相对悲观锁而言Q乐观锁机制采取了更加宽杄加锁机制。悲观锁大多数情况下?靠数据库的锁机制实现Q以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销Q特别是寚w事务而言Q这L开销往往无法承受?如一个金融系l,当某个操作员d用户的数据,q在d的用h据的基础上进 行修ҎQ如更改用户帐户余额Q,如果采用悲观锁机Ӟ也就意味着整个操作q?E中Q从操作员读出数据、开始修改直x交修改结果的全过E,甚至q包括操?员中途去煮咖啡的旉Q,数据库记录始l处于加锁状态,可以惌Q如果面对几 百上千个q发Q这L情况导致怎样的后果?乐观锁机制在一定程度上解决了这个问题?font color="#ff0000">乐观?大多是基于数据版?QVersionQ记录机制实?/strong>。何谓数据版本?即ؓ数据增加一个版本标识,在基?数据库表的版本解x案中Q一般是通过为数据库表增加一个“version”字D| 实现?d出数据时Q将此版本号一同读出,之后更新ӞҎ版本号加一。此Ӟ提 交数据的版本数据与数据库表对应记录的当前版本信息q行比对Q如果提交的数据 版本号大于数据库表当前版本号Q则予以更新Q否则认为是q期数据?对于上面修改用户帐户信息的例子而言Q假?Q?br />
数据库中帐户信息表中有一?version字段Q当前gؓ1Q而当前帐户余额字D(balanceQؓ$100?
1 Q操作员A 此时其dQversion=1Q,q从其帐户余额中扣除$50 Q?100-$50Q?
2 Q 在操作员A操作的过E中Q操作员B也读入此用户信息Qversion=1Q,q?从其帐户余额中扣?20Q?100-$20Q?
3Q?操作员A完成了修改工作,数据版本号加一Qversion=2Q,q同帐户?除后余额Qbalance=$50Q,提交x据库更新Q此时由于提交数据版本大 于数据库记录当前版本Q数据被更新Q数据库记录version更新??
4Q?操作员B完成了操作,也将版本号加一Qversion=2Q试囑֐数据库提交数 据(balance=$80Q,但此时比Ҏ据库记录版本时发玎ͼ操作员B提交?数据版本号ؓ2Q数据库记录当前版本也ؓ2Q不满“提交版本必d于记 录当前版本才能执行更新“的乐观锁策略,因此Q操作员B 的提交被驛_?q样Q就避免了操作员B 用基于version=1 的旧数据修改的结果覆盖操?员A的操作结果的可能?

从上面的例子可以看出Q乐观锁机制避免了长事务中的数据库加锁开销Q操作员A 和操作员B操作q程中,都没有对数据库数据加锁)Q大大提升了大ƈ发量下的p?l整体性能表现?需要注意的是,乐观锁机制往往Zpȝ中的数据存储逻辑Q因此也具备一定的局 限性,如在上例中,׃乐观锁机制是在我们的pȝ中实玎ͼ来自外部pȝ的用?余额更新操作不受我们pȝ的控Ӟ因此可能会造成脏数据被更新到数据库中。在 pȝ设计阶段Q我们应该充分考虑到这些情况出现的可能性,q进行相应调_?乐观锁{略在数据库存储q程中实玎ͼ对外只开攑֟于此存储q程的数据更新?径,而不是将数据库表直接对外公开Q?Hibernate 在其数据讉K引擎中内|了乐观锁实?/strong>。如果不用考虑外部pȝҎ 据库的更新操作,利用Hibernate提供的透明化乐观锁实现Q将大大提升我们?生力?Hibernate中可以通过class描述W的optimistic-lock属性结合version 描述W指定?
现在Q我们ؓ之前CZ中的TUser加上乐观锁机制?br /> 
1Q?首先为TUser的class描述W添加optimistic-lock属性:

< hibernate - mapping >  
< class  
name
= " org.hibernate.sample.TUser "  
table
= " t_user "  
dynamic
- update = " true "  
dynamic
- insert = " true "  
optimistic
- lock = " version "  
>  
……?br />
</ class >  
</ hibernate - mapping >  

optimistic-lock属性有如下可选取|
? none 无乐观锁
? version 通过版本机制实现乐观?
? dirty 通过查发生变动过的属性实C观锁
? all 通过查所有属性实C观锁

其中通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现Q同时也 是Hibernate中,目前唯一在数据对象脱Session发生修改的情况下依然有效的锁??/u>。因此,一般情况下Q我们都选择version方式作ؓHibernate乐观锁实现机制?

2Q?d一个Version属性描q符
代码内容

 1 < hibernate - mapping >   
 2 < class   
 3 name = " org.hibernate.sample.TUser "   
 4 table = " t_user "   
 5 dynamic - update = " true "   
 6 dynamic - insert = " true "   
 7 optimistic - lock = " version "   
 8 >   
 9 < id  
10 name = " id "   
11 column = " id "   
12 type = " java.lang.Integer "   
13 >   
14 < generator  class = " native " >   
15 </ generator >   
16 </ id >   
17 < version  
18 column = " version "   
19 name = " version "   
20 type = " java.lang.Integer "   
21 />   
22 …… ?br /> 23 </ class >   
24 </ hibernate - mapping >   
25

注意version 节点必须出现在ID 节点之后?q里我们声明了一个version属性,用于存放用户的版本信息,保存在TUser表的 version字段中?此时如果我们试~写一D代码,更新TUser表中记录数据Q如Q?
代码内容

1 Criteria criteria  =  session.createCriteria(TUser. class );  
2 criteria.add(Expression.eq( " name " , " Erica " ));  
3 List userList  =  criteria.list();  
4 TUser user  = (TUser)userList.get( 0 );  
5 Transaction tx  =  session.beginTransaction();  
6 user.setUserType( 1 );  // 更新UserType字段  
7 tx.commit();  
8

每次对TUserq行更新的时候,我们可以发现Q数据库中的version都在递增?而如果我们尝试在tx.commit 之前Q启动另外一个SessionQ对名ؓErica 的用 戯行操作,以模拟ƈ发更新时的情形:
代码内容

 1 Session session =  getSession();  
 2 Criteria criteria  =  session.createCriteria(TUser. class );  
 3 criteria.add(Expression.eq( " name " , " Erica " ));  
 4 Session session2  =  getSession();  
 5 Criteria criteria2  =  session2.createCriteria(TUser. class );  
 6 criteria2.add(Expression.eq( " name " , " Erica " ));  
 7 List userList  =  criteria.list();  
 8 List userList2  =  criteria2.list();TUser user  = (TUser)userList.get( 0 );  
 9 TUser user2  = (TUser)userList2.get( 0 );  
10 Transaction tx  =  session.beginTransaction();  
11 Transaction tx2  =  session2.beginTransaction();  
12 user2.setUserType( 99 );  
13 tx2.commit();  
14 user.setUserType( 1 );  
15 tx.commit();  
16

执行以上代码Q代码将在tx.commit()处抛?font color="#0000ff">StaleObjectStateException?常,q指出版本检查失败,当前事务正在试图提交一个过期数据。通过捕捉q个异常Q我 们就可以在乐观锁校验p|时进行相应处理?



rendong 2006-12-27 16:40 发表评论
]]>
c3p0http://www.tkk7.com/rendong/archive/2006/12/02/85058.htmlrendongrendongSat, 02 Dec 2006 09:32:00 GMThttp://www.tkk7.com/rendong/archive/2006/12/02/85058.htmlhttp://www.tkk7.com/rendong/comments/85058.htmlhttp://www.tkk7.com/rendong/archive/2006/12/02/85058.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/85058.htmlhttp://www.tkk7.com/rendong/services/trackbacks/85058.html<session-factory>

<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
<property name="show_sql">true</property>
<property name="current_session_context_class">thread</property>
<!--Fetch Size 是设定JDBC的Statementd数据的时候每ơ从数据库中取出的记录条?->
<property name="jdbc.fetch_size">20</property>
<!--Batch Size是设定对数据库进行批量删除,扚w更新和批量插入的时候的Ҏ大小Q有点相当于讄Buffer~冲区大的意?->
<property name="jdbc.batch_size ">20</property>
<property name="connection.username">HNMC</property>
<property name="connection.password">sundy</property>
<property name="connection.url">jdbc:oracle:thin:@192.168.0.20:1521:ora9</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

<!--  在这U情况下Q没问题?-->
<property name="c3p0.timeout">60</property>
<property name="c3p0.idle_test_period">600</property>


<!--    

<!--<property name="c3p0.idle_test_period">120</property>-->
如改以下俩|或他们差距很大:

<property name="c3p0.timeout">600</property>

<!--<property name="c3p0.idle_test_period">60</property>-->

当我启动tomcatQ运行程序后Q空?00后出C列异?但程序还照常q行

-->

<!-- 

Hibernate里可以设|的属性不多:
#c3p0-native property name hibernate configuration key
#c3p0.acquireIncrement hibernate.c3p0.acquire_increment
#c3p0.idleConnectionTestPeriod hibernate.c3p0.idle_test_period
#c3p0.initialPoolSize not available -- uses minimum size
#c3p0.maxIdleTime hibernate.c3p0.timeout
#c3p0.maxPoolSize hibernate.c3p0.max_size
#c3p0.maxStatements hibernate.c3p0.max_statements
#c3p0.minPoolSize hibernate.c3p0.min_size
#c3p0.testConnectionsOnCheckout hibernate.c3p0.validate hibernate 2.x only!

另外的属性你需要配|c3p0.properties
比如Q?
c3p0.acquireRetryDelay=111
c3p0.acquireRetryAttempts=22
c3p0.breakAfterAcquireFailure=true

-->



<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_size">2</property>
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.timeout">50000</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>

<!-- ?lt;property name="hibernate.c3p0.validate">false</property>实在hibernate中不可设| ?->
<property name="hibernate.c3p0.validate">false</property>


<!--C3P0 setting-->

<property name="c3p0.max_size">20</property>
<property name="c3p0.min_size">5</property>
<!--获取q接的等待时?->
<property name="c3p0.timeout">3600</property>
<property name="c3p0.max_statements">100</property>
<!--每隔3600毫秒试q接是否可以正常使用-->
<property name="c3p0.idle_test_period">3600</property>
<property name="c3p0.acquire_increment">2</property>

<mapping resource="com/sundy/hnmc/beans/AccountBean.hbm.xml"/>
</session-factory>
</hibernate-configuration>



另一个设|?br /> <!-- 数据源配|?/span>-->
    
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
      
<property name="driverClass">
        
<value>org.gjt.mm.mysql.Driver</value>
      
</property>
      
<property name="jdbcUrl">
        
<value>jdbc:mysql://localhost/tycho?useUnicode=true&amp;characterEncoding=utf-8</value>
      
</property>
      
<property name="properties">
        
<props>
            
<prop key="hibernate.hbm2ddl.auto">update</prop> 
            
<prop key="c3p0.minPoolSize">1</prop> 
            
<prop key="hc3p0.maxPoolSize">10</prop> 
            
<prop key="hc3p0.timeout">60</prop> 
            
<prop key="c3p0.max_statement">50</prop> 
            
<prop key="c3p0.testConnectionOnCheckout">true</prop> 
            
<prop key="hibernate.c3p0.testConnectionOnCheckout">false</prop>
            
<prop key="user">root</prop> 
            
<prop key="password">root</prop>
        
</props>
      
</property>
    
</bean>



<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.timeout">120</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">120</property>
<property name="hibernate.c3p0.acquire_increment">2</property>


 

 

 

 



rendong 2006-12-02 17:32 发表评论
]]>
好的|址http://www.tkk7.com/rendong/archive/2006/09/03/67343.htmlrendongrendongSat, 02 Sep 2006 16:44:00 GMThttp://www.tkk7.com/rendong/archive/2006/09/03/67343.htmlhttp://www.tkk7.com/rendong/comments/67343.htmlhttp://www.tkk7.com/rendong/archive/2006/09/03/67343.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/67343.htmlhttp://www.tkk7.com/rendong/services/trackbacks/67343.htmlhttp://blog.csdn.net/baggio785/

http://tag.csdn.net/tag/hibernate/1.html

rendong 2006-09-03 00:44 发表评论
]]>
1.1 Hibernate API 变化 http://www.tkk7.com/rendong/archive/2006/09/03/67341.htmlrendongrendongSat, 02 Sep 2006 16:41:00 GMThttp://www.tkk7.com/rendong/archive/2006/09/03/67341.htmlhttp://www.tkk7.com/rendong/comments/67341.htmlhttp://www.tkk7.com/rendong/archive/2006/09/03/67341.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/67341.htmlhttp://www.tkk7.com/rendong/services/trackbacks/67341.htmlapi com hibernate ice java os sql 函数 软g 
选自《精通HibernateQJava对象持久化技术详解》 作者:孙卫琾b来? www.javathinker.org 
如果转蝲Q请标明出处Q谢谢?br />
1.1 Hibernate API 变化 
1.1.1 包名 
1.1.2 org.hibernate.classic包?br />1.1.3 Hibernate所依赖的第三方软g包?br />1.1.4 异常模型 
1.1.5 Session接口 
1.1.6 createSQLQuery() 
1.1.7 Lifecycle 和 Validatable 接口 
1.1.8 Interceptor接口 
1.1.9 UserType和CompositeUserType接口 
1.1.10 FetchModec?br />1.1.11 PersistentEnumc?br />1.1.12 对Blob 和Clob的支持?br />1.1.13 Hibernate中供扩展的API的变化?br />1.2 元数据的变化 
1.2.1 索策略?br />1.2.2 对象标识W的映射 
1.2.3 集合映射 
1.2.4 DTD 
1.3 查询语句的变化?br />1.3.1 indices()和elements()函数 


管Hibernate 3.0 与Hibernate2.1的源代码是不兼容的,但是当Hibernate开发小l在设计Hibernate3.0Ӟ为简化升UHibernate版本作了周到的考虑。对于现有的ZHibernate2.1的Java目Q可以很方便的把它升U到Hibernate3.0。?br />
本文描述了Hibernate3.0版本的新变化QHibernate3.0版本的变化包括三个方面: 
Q?QAPI的变化,它将影响到JavaE序代码。?br />Q?Q元数据Q它媄响到对象-关系映射文g。?br />Q?QHQL查询语句。?br />
值得注意的是Q Hibernate3.0q不会完全取代Hibernate2.1。在同一个应用程序中Q允许Hibernate3.0和Hibernate2.1q存。?br />
1.1 Hibernate API 变化 

1.1.1 包名 

Hibernate3.0的包的根路径? “org.hibernate” ,而在Hibernate2.1中ؓ“net.sf.hibernate”。这一命名变化使得Hibernate2.1和Hibernate3.0能够同时在同一个应用程序中q行。?br />
如果希望把已有的应用升到Hibernate3.0Q那么升U的W一步是把Java源程序中的所有“net.sf.hibernate”替换ؓ“org.hibernate”。?br />
Hibernate2.1中的“net.sf.hibernate.expression”包被改名ؓ“org.hibernate.criterion”。假如应用程序用了Criteria APIQ那么在升的过E中Q必LJava源程序中的所有“net.sf.hibernate.expression”替换ؓ“org.hibernate.criterion”。?br />
如果应用使用了除Hibernate以外的其他外部YӞ而这个外部Y件又引用了Hibernate的接口,那么在升U时必须十分心。例如EHCache拥有自己的CacheProviderQ net.sf.ehcache.hibernate.ProviderQ在q个cM引用了Hibernate2.1中的接口Q在升应用Ӟ可以采用以下办法之一来升UEHCache: 

Q?Q手工修改net.sf.ehcache.hibernate.Providerc,使它引用Hibernate3.0中的接口。?br />Q?Q等到EHCache软g本n升Z用Hibernate3.0后,使用新的EHCache软g。?br />Q?Q用Hibernate3.0中内|的CacheProviderQorg.hibernate.cache.EhCacheProvider。?br />
1.1.2 org.hibernate.classic包?br />
Hibernate3.0把一些被废弃的接口都转移到org.hibernate.classic中。?br />
1.1.3 Hibernate所依赖的第三方软g包?br />
在Hibernate3.0的Y件包的lib目录下的README.txt文g中,描述了Hibernate3.0所依赖的第三方软g包的变化。?br />
1.1.4 异常模型 

在Hibernate3.0中,HibernateException异常以及它的所有子c都l承了java.lang.RuntimeException。因此在~译Ӟ~译器不会再查HibernateException。?br />
1.1.5 Session接口 

在Hibernate3.0中,原来Hibernate2.1的Session接口中的有些基本Ҏ也被废弃Q但Z化升U,q些Ҏ依然是可用的Q可以通过org.hibernate.classic.Session子接口来讉K它们Q例如: 
org.hibernate.classic.Session session=sessionFactory.openSession(); 
session.delete("delete from Customer "); 
在Hibernate3.0中,org.hibernate.classic.Session接口l承了org.hibernate.Session接口Q在org.hibernate.classic.Session接口中包含了一pd被废弃的ҎQ如find()、interate(){。SessionFactory接口的openSession()Ҏq回org.hibernate.classic.Sessioncd的实例。如果希望在E序中完全用Hibernate3.0Q可以采用以下方式创建Session实例Q?br />
org.hibernate.Session session=sessionFactory.openSession(); 

如果是对已有的程序进行简单的升Qƈ且希望仍然调用Hibernate2.1中Session的一些接口,可以采用以下方式创徏Session实例Q?br />
org.hibernate.classic.Session session=sessionFactory.openSession(); 

在Hibernate3.0中,Session接口中被废弃的方法包括: 
* 执行查询的方法:find()、iterate()、filter()和delete(String hqlSelectQuery) 
* saveOrUpdateCopy() 

Hibernate3.0一律采用createQuery()Ҏ来执行所有的查询语句Q采用DELETE 查询语句来执行批量删除,采用merge()Ҏ来替代 saveOrUpdateCopy()Ҏ。?br />
提示Q在Hibernate2.1中,Session的delete()Ҏ有几U重载Ş式,其中参数为HQL查询语句的delete()Ҏ在Hibernate3.0中被废弃Q而参CؓOjbectcd的的delete()Ҏ依然被支持。delete(Object o)Ҏ用于删除参数指定的对象,该方法支持联删除。?br />Hibernate2.1没有Ҏ量更新和扚w删除提供很好的支持,参见<<_NHibernate>>一书的W?3章的13.1.1节(扚w更新和批量删除)Q而Hibernate3.0Ҏ量更新和扚w删除提供了支持,能够直接执行扚w更新或批量删除语句,无需把被更新或删除的对象先加载到内存中。以下是通过Hibernate3.0执行扚w更新的程序代码: 
Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
String hqlUpdate = "update Customer set name = :newName where name = :oldName"; 
int updatedEntities = s.createQuery( hqlUpdate ) 
.setString( "newName", newName ) 
.setString( "oldName", oldName ) 
.executeUpdate(); 
tx.commit(); 
session.close(); 
以下是通过Hibernate3.0执行扚w删除的程序代码: 
Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
String hqlDelete = "delete Customer where name = :oldName"; 
int deletedEntities = s.createQuery( hqlDelete ) 
.setString( "oldName", oldName ) 
.executeUpdate(); 
tx.commit(); 
session.close(); 

1.1.6 createSQLQuery() 

在Hibernate3.0中,Session接口的createSQLQuery()Ҏ被废弃,被移到org.hibernate.classic.Session接口中。Hibernate3.0采用新的SQLQuery接口来完成相同的功能。?br />
1.1.7 Lifecycle 和 Validatable 接口 

Lifecycle和Validatable 接口被废弃,q且被移到org.hibernate.classic包中。?br />
1.1.8 Interceptor接口 

在Interceptor 接口中加入了两个新的Ҏ。 用户创建的Interceptor实现cd升的过E中Q需要ؓq两个新Ҏ提供Ҏ体ؓI的实现。此外,instantiate()Ҏ的参C了修改,isUnsaved()Ҏ被改名ؓisTransient()。?br />
1.1.9 UserType和CompositeUserType接口 

在UserType和CompositeUserType接口中都加入了一些新的方法,q两个接口被Udorg.hibernate.usertype包中Q用户定义的UserType和CompositeUserType实现cdd现这些新Ҏ。?br />Hibernate3.0提供了ParameterizedType接口Q用于更好的重用用户自定义的cd。?br />1.1.10 FetchModec?br />
FetchMode.LAZY 和 FetchMode.EAGER被废弃。取而代之的分别为FetchMode.SELECT 和FetchMode.JOIN。?br />
1.1.11 PersistentEnumc?br />
PersistentEnum被废弃ƈ删除。已l存在的应用应该采用UserType来处理枚丄型。?br />
1.1.12 对Blob 和Clob的支持?br />
Hibernate对Blob和Clob实例q行了包装,使得那些拥有Blob或Clobcd的属性的cȝ实例可以被游R序列化或反序列化,以及传递到merge()Ҏ中。?br />
1.1.13 Hibernate中供扩展的API的变化?br />
org.hibernate.criterion、 org.hibernate.mapping、 org.hibernate.persister和org.hibernate.collection 包的l构和实现发生了重大的变化。多数基于Hibernate 
2.1 的应用不依赖于这些包Q因此不会被影响。如果你的应用扩展了q些包中的类Q那么必非常小心的对受影响的程序代码进行升U。?br />
1.2 元数据的变化 

1.2.1 索策略?br />
在Hibernate2.1中,lazy属性的默认gؓ“false”,而在Hibernate3.0中,lazy属性的默认gؓ“true”。在升映射文gӞ如果原来的映文件中的有兛_素,如、等没有昑ּ讄lazy属性,那么必须把它们都昑ּ的设|ؓlazy=“true”。如果觉得这U升U方式很ȝQ可以采取另一单的升方式Q在元素中设|? default-lazy=“false”。?br />
1.2.2 对象标识W的映射 

unsaved-value属性是可选的Q在多数情况下,Hibernate3.0把unsaved-value="0" 作ؓ默认倹{?br />
在Hibernate3.0中,当用自然主键和游离对象Ӟ不再实现Interceptor.isUnsaved()Ҏ。 如果没有设|这个方法,当Hibernate3.0无法区分对象的状态时Q会查询数据库,来判断这个对象到底是临时对象Q还是游d象。不q,昑ּ的用Interceptor.isUnsaved()Ҏ会获得更好的性能Q因可以减少Hibernate直接讉K数据库的ơ数。?br />
1.2.3 集合映射 

元素在某些情况下被和元素替代。此外,Hibernate3.0用 元素来替代原来?元素Q用元素来替代原来的元素。?br />
1.2.4 DTD 

对象-关系映射文g中的DTD文档Q由原来的: 
http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd 
改ؓQ?br />http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd 

1.3 查询语句的变化?br />
Hibernate3.0 采用新的ZANTLR的HQL/SQL查询译器,不过QHibernate2.1的查询翻译器也依然存在。在Hibernate的配|文件中Qhibernate.query.factory_class属性用来选择查询译器。例如: 
Q?Q选择Hibernate3.0的查询翻译器Q?br />hibernate.query.factory_class= org.hibernate.hql.ast.ASTQueryTranslatorFactory 
Q?Q选择Hibernate2.1的查询翻译器 
hibernate.query.factory_class= org.hibernate.hql.classic.ClassicQueryTranslatorFactory 

提示QANTLR是用UJava语言~写出来的一个编译工P它可生成Java语言或者是C++的词法和语法分析器,q可产生语法分析树ƈ对该树进行遍历。ANTLR׃是纯Java的,因此可以安装在Q意^CQ但是需要JDK的支持。?br />Hibernate开发小l尽力保证Hibernate3.0的查询翻译器能够支持Hibernate2.1的所有查询语句。不q,对于许多已经存在的应用,在升U过E中Q也不妨仍然使用Hibernate2.1的查询翻译器。?br />值得注意的是Q Hibernate3.0的查询翻译器存在一个BugQ不支持某些theta-styleq结查询方言Q如Oracle8i的OracleDialect方言、Sybase11Dialect。解册一问题的办法有两种Q(1Q改Z用支持ANSI-styleq结查询的方aQ如 Oracle9Dialect,Q?Q如果升U的时候遇到这一问题Q那么还是改Z用Hibernate2.1的查询翻译器。?br />
1.3.1 indices()和elements()函数 

在HQL的select子句中废弃了indices()和elements()函数Q因两个函数的语法很让用戯解,可以用显式的q接查询语句来替代 select elements(...) 。而在HQL的where子句中,仍然可以使用elements()函数?br />

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=623674



rendong 2006-09-03 00:41 发表评论
]]>
大大z洒http://www.tkk7.com/rendong/archive/2006/09/03/67339.htmlrendongrendongSat, 02 Sep 2006 16:37:00 GMThttp://www.tkk7.com/rendong/archive/2006/09/03/67339.htmlhttp://www.tkk7.com/rendong/comments/67339.htmlhttp://www.tkk7.com/rendong/archive/2006/09/03/67339.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/67339.htmlhttp://www.tkk7.com/rendong/services/trackbacks/67339.html2006/5/16

hibernate中session.delete(sql),3.1?.0的区?D的错?/h4>
今天使用session.delete(sql);报下面的错误:
 
org.hibernate.MappingException: Unknown entity: java.lang.String
 at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:569)
 at org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1086)
 at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:63)
 at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:579)
 
查查l于知道原因:
 
    session.delete(sql)?.0的接?3.1中已l废?同时废弃的有:
    find()、iterate()、filter()和delete(String hqlSelectQuery),saveOrUpdateCopy()
 
  如果要用的?可以采用以下方式创徏Session实例Q?br />
      org.hibernate.classic.Session session=sessionFactory.openSession(); 
 
      org.hibernate.classic.Session保留?.0的接?/div>
 
下面?.1的reference里面q样写的,我用了,但是q是报错,郁闷:
 
1) Hibernate3.0执行扚w删除的程序代码: 
Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
String hqlDelete = "delete Customer where name = :oldName"; 
int deletedEntities = s.createQuery( hqlDelete ) 
.setString( "oldName", oldName ) 
.executeUpdate(); 
tx.commit(); 
session.close();
 
2)Hibernate3.0执行扚w更新的程序代码: 
Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
String hqlUpdate = "update Customer set name = :newName where name = :oldName"; 
int updatedEntities = s.createQuery( hqlUpdate ) 
.setString( "newName", newName ) 
.setString( "oldName", oldName ) 
.executeUpdate(); 
tx.commit(); 
session.close(); 
 
我按照上面的写法,q行后报错如?

org.hibernate.QueryException: query must begin with SELECT or FROM: delete [delete Resource r where r.nodeId=:nodeId and r.devId is not null ]
 at org.hibernate.hql.classic.ClauseParser.token(ClauseParser.java:83)
 at org.hibernate.hql.classic.PreprocessingParser.token(PreprocessingParser.java:108)
 at org.hibernate.hql.classic.ParserHelper.parse(ParserHelper.java:28)
 at org.hibernate.hql.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:176)
 at org.hibernate.hql.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:152)
 at org.hibernate.impl.SessionFactoryImpl.getQuery(SessionFactoryImpl.java:427)
 at org.hibernate.impl.SessionImpl.getQueries(SessionImpl.java:884)
 at org.hibernate.impl.SessionImpl.executeUpdate(SessionImpl.java:865)
 at org.hibernate.impl.QueryImpl.executeUpdate(QueryImpl.java:89)


昨天的问题解决了

又把hibernate3的手册仔l的看了一?认自己的写法是没错?然后又上hibernate的论?几乎没有人有我的q个问题,q才惛_是不是同事在hibernate.hbm.xml中设|了什么参?使得我不能?.0的特性呢?
      看了,果真如此,郁闷哦~
     里面有一?
     <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property>
     q样׃用了2.0的接?郁闷?
     把这句去掉就OK?
 
     ?
      因ؓ使用了中文拼装的hql?中文会变成问?大致如下:
 
      String hql="from user u where u.name like %"+userName+"%";
 
      3.0版本?
      Query query = session.createQuery("from user u where u.name like :username").setString("username",userName);




现在要通过一个主键idL据库中删除对应的一条记录,我该怎样做?如果是将参数delId传递进来的话,那该怎么处理Q? 我这样做的,但是报了? 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)
回复人:pdvv(我爱q) 2006-3-1 17:32:22得分:0
?
你给出的异常应该属于你自己框架的信息吧,没有多少参考h倹{? 使用Session.load()要确保数据一定存在,q是用get()吧; 或者直接session.delete("from INFO where ID = 1");
Top
回复人:yuanjian0211(元剑) 2006-3-1 17:46:04得分:0
?
错误提示信息为: 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=? h?
Top
回复人:yuanjian0211(元剑) 2006-3-1 17:56:29得分:0
?
id在数据库表中为bigint? 在对象中为long?
Top
回复人:iori_powermax() 2006-03-02 01:06:00得分:0
?
我也在学习hibernate,不知道说的对不对. 你删除的应该是整个对?而不是一个id,所以应该ؓ: Info info = (Info)session.load(Info.class,id); session.delete(info); 或者还有一U删除记录的Ҏ: info=(Info)sn.creatQuery("from Info as a where a.ID= '"+delId+"'").uniqueResult(); sn.delete(info); 另外想问一下大? hibernate的creatSQLQuery()是不是只支持查询?好象增删攚w不可?
Top
回复人:ymfhcn(q痞子真? 2006-03-02 08:06:00得分:0
?
creatSQLQuery()是执行sql语句的,不过E微有些改动Q里面什么SQL语句都可以写



 | = | 一般分c?/a> | 仙侠修真 | VBScript | .NET | 面试?/a> | 存储q程 | Hibernate | JavaScript | J2EE | Struts
自我介绍
切换风格
订阅我的Blog
博客日历
文章归档...
最新发?..
博客l计...
|站链接...
资源
===========================================================
Hibernate ?session.delete(obj
===========================================================

session.delete(obj)obj的状态变为transient。两U情?/strong>
1Qobj是session的cache里边的cache没有的,比如Q?br />session.delete(new Employee(4));
2Qobj存在于session的cache中,比如Q?br />Employee employee = (Employee)session.load(Employee.class, new Integer(4));
session.delete(employee);

q两U情况都是允许的Qhibernate都会发送一条delete语句l数据库?/p>

delete执行之后Q如果调用了session.load(), 又可以分ZU情况:1Q在session.flush()之前Q如Q?br />tx.beginTransaction();
    session.delete(new Employee(4));
session.load(Employee.class, new Integer(4));//发生在session.flush()之前
tx.commit();
那么hibernate会抛出ObjectDeletedException:The object with that id was deleted:

2Q在session.flush()之后Q如Q?br />tx.beginTransaction();
    session.delete(new Employee(4));
session.load(Employee.class, new Integer(4));
tx.commit();

tx.beginTransaction();
session.load(Employee.class, new Integer(4));//同一个session中,上面的tx.commit()session flush了一ơ?br />tx.commit();
那么q个时候hibernate仅仅会抛出ObjectNotFoundException:No row with the give...
表示找不到该object。如果第二个tx里边采用session.get()也就不会抛出exception了?/p>

delete执行之后Q如果调用了session.save(obj):
tx.beginTransaction();
Employee employee = (Employee)session.load(Employee.class, new Integer(4));
    session.delete(employee);
System.out.println(employee);
session.save(employee);
System.out.println(employee);
tx.commit();
q种情况是完全合理的Q合法的?br />deleteemployee从persistent的状态变为transient的状态?br />saveemployee从transient状态变为persistent的状态?/strong>save一个被delete的obj的时候,在save处hibernate强制执行session.flush()Q发送delete语句Q然后按照常规的save程来进行。ؓ什么要q么做,q没有完全想明白?br />
delete执行之后Q如果对obj对象属性的修改Qtx.commit()时不会进行dirtyChecking?/font>
q个道理比较昄?/p>

- 作者: HairRoot 2005q?5?/p>




hibernateq接sqlserver2000问题的解?/h4>
q几天在q行数据库的UL,oracle数据库的东西UL到mssqlserver 2000?/div>
 
其中q行一个查询的时?报如下的错误:
 
 [Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode.
 
解决办法:
   <property name="connection.url">
     jdbc:microsoft:sqlserver://192.168.1.110:2433;SelectMethod=cursor
  </property>
 
(U色为增加的)
 
原因:
   1.    处于手动事务状?q且使用direct模式,因ؓhibernate默认为direct模式,
         ?/font> SelectMethod=direct
   2.    在一个SQL SERVER的JDBCq接上执行多个STATEMENTS的操?/font>


强的脓,每句都是l典
水至清则无鱼,贱则无敌! 走自q路,让别人打车去吧。穿别h的鞋Q走自己的\Q让他们扑֎吧。打台湾我捐一个月的生z费Q打国我捐一q的生活费, 打日本我捐他妈的一条命! 我不是随便的人,我随便v来不是h。女人无所谓正z,正派是因为受到的引诱不够Q男人无所谓忠诚,忠诚是因叛的{码太低…?骑白马的不一定是王子Q可能是唐僧Q带膀的也不一定是天Q有时候是鸟h?俺的最低奋斗目标:农妇Q山泉,有点田。再q几十年Q我们来怼Q送到火葬场,全部烧成灎ͼ你一堆,我一堆,谁也不认识谁Q全部送到农村做化?br />



http://iceling2008.itpub.net/category/13270/23134好东西       ?阿法?br />http://comsmall.spaces.live.com/PersonalSpace.aspx?_c02_owner=1


遇到 "Automation服务器不能创建对?/font>"

q行 Regsvr32 scrrun.dll?/font>



rendong 2006-09-03 00:37 发表评论
]]>高 DAO ~程 http://www.tkk7.com/rendong/archive/2006/08/31/66964.htmlrendongrendongThu, 31 Aug 2006 15:16:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/31/66964.htmlhttp://www.tkk7.com/rendong/comments/66964.htmlhttp://www.tkk7.com/rendong/archive/2006/08/31/66964.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/66964.htmlhttp://www.tkk7.com/rendong/services/trackbacks/66964.html

高 DAO ~程

学习~译更好?DAO 的技?/p> developerWorks
文档选项
此作为电子邮件发? src=

此作为电子邮件发?/font>

未显C需?JavaScript 的文档选项


最新推?/td>

Java 应用开发源动力 Q?下蝲免费软gQ快速启动开?/font>


U别: 初

Sean C. Sullivan , 软g工程?br />

2003 q?10 ?15 ?/p>

J2EE 开发h员用数据访问对?Data Access Object DAO)设计模式Q以便将低别的数据讉K逻辑与高U别的业务逻辑分离。实?DAO 模式涉及比编写数据访问代码更多的内容。在本文中,Java 开发h?Sean C. Sullivan 讨论?DAO ~程中三个常常被忽略的方面:事务界定、异常处理和日志记录?/blockquote>

在过?18 个月中,我参加了一个由有才华的软g工程师组成的组Q构建定制的、基?Web 的供应链理应用E序。我们的应用E序讉K范围q泛的持久性数据,包括配送状态、供应链衡量(metrics)、库存、货q发、项目管理数据和用户信息。我们用 JDBC API q接到我们公司的不同数据库^CQƈ在整个应用程序中使用 DAO 设计模式?/p>

?1 昄了应用程序和数据源之间的关系Q?/p>
?1. 应用E序和数据源
应用E序和数据源

在整个应用程序中使用数据讉K对象(DAO)使我们可以将底层数据讉K逻辑与业务逻辑分离开来。我们构Z为每一个数据源提供 GRUD (创徏、读取、更新、删?操作?DAO cR?/p>

在本文中Q我ؓ您介l构建更好的 DAO cȝ DAO 实现{略和技术。更切地说Q我讨论日志、异常处理和事务界定。您学到如何将q三者结合到自己?DAO cM。本文假定您熟悉 JDBC API、SQL 和关pL据库~程?/p>

我们以?DAO 设计模式和数据访问对象的概述开始?/p>

DAO基础

DAO 模式是标?J2EE 设计模式之一。开发h员用q种模式底层数据访问操作与高层业务逻辑分离开。一个典型的 DAO 实现有以下组Ӟ

  • 一?DAO 工厂c?
  • 一?DAO 接口
  • 一个实C DAO 接口的具体类
  • 数据传输对象(有时UCؓ值对?

具体?DAO cd含访问特定数据源的数据的逻辑。在下面一节中您将学习设计和实现数据访问对象的技术。有?DAO 设计模式的更多内容请参阅 参考资?/font>?





回页?/font>


事务界定

关于 DAO 要记住的重要一Ҏ它们是事务性对象。由 DAO 所执行的每一个操?-- 如创建、更新或者删除数?-- 都与一个事务相兌。因此, 事务界定的概念就变得特别重要了?

事务界定是定义事务边界的方式。J2EE 规范描述了两U事务界定的模型Q编E式(programmatic)和声明式(declarative)。表 1 分析了这两种模型Q?/p>

?1. 两种事务界定的模?/font>

声明式事务界?/strong> ~程式事务界?/b>
E序员用 EJB 部v描述W声明事务属性?/td> E序员负责编写事务逻辑?/td>
q行时环?EJB 容器)用这些属性自动管理事务?/td> 应用E序通过一?API 控制事务?/td>

我们侧重于~程式事务界定?/p>

设计考虑

如前所qͼDAO 是事务性对象。一个典型的 DAO 执行像创建、更新和删除q样的事务性操作。在设计 DAO Ӟ首先要问自己以下问题Q?/p>

  • 事务要如何开始?
  • 事务应如何结束?
  • 哪一个对象将负责开始一个事务?
  • 哪一个对象将负责l束一个事务?
  • DAO 是否要负责事务的开始和l束Q?
  • 应用E序是否需要通过多个 DAO 讉K数据Q?
  • 事务涉及C?DAO q是多个 DAOQ?
  • 一?DAO 是否调用另一?DAO 的方法?

了解上述问题的答案将有助于您选择最适合?DAO 的事务界定策略。在 DAO 中有两种主要的界定事务的{略。一U方式是?DAO 负责界定事务Q另一U将事务界定交给调用q个 DAO Ҏ的对象处理。如果选择了前一U方式,那么将事务代码嵌入?DAO 中。如果选择后一U方式,那么事务界定代码是?DAO cd面。我们将使用单的代码CZ帮助您更好理解每一U方式是如何工作的?/p>

清单 1 昄了一个有两种数据操作?DAOQ创建和更新Q?/p>
清单 1. DAO Ҏ
												
														       public void createWarehouseProfile(WHProfile profile);
       public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);

												
										

清单 2 昄了一个简单的事务。事务界定在 DAO cd面。注意在q个例子中调用者是如何在一个事务中l合多个 DAO 操作的?/p>
清单 2. 调用者管理的事务
												
														      tx.begin();    // start the transaction
      dao.createWarehouseProfile(profile);
      dao.updateWarehouseStatus(id1, status1);
      dao.updateWarehouseStatus(id2, status2);
      tx.commit();   // end the transaction

												
										

q种事务界定{略对于需要在一个事务中讉K多个 DAO 的应用程序特别有用?/p>

可以?JDBC API 或?Java 事务 API(Java Transaction API JTA)实现事务界定?JDBC 事务界定?JTA 事务界定要简单,但是 JTA 提供了更多的灉|性。在下面一节中我将更深入地分析事务界定的机制?/p>



回页?/font>


?JDBC q行事务界定

JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两U事务模式:自动提交和手工提交?java.sql.Connection 提供了以下控制事务的ҎQ?

  • public void setAutoCommit(boolean)
  • public boolean getAutoCommit()
  • public void commit()
  • public void rollback()

清单 3 昄了如何用 JDBC API 界定一个事务:


清单 3. ?JDBC API q行事务界定
												
														      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();
      // ...

												
										

使用 JDBC 事务界定Ӟ您可以将多个 SQL 语句l合C个事务中。JDBC 事务的一个缺Ҏ事务的范围局限于一个数据库q接。一?JDBC 事务不能跨越多个数据库。在下面Q我们将看一下如何用 JTA q行事务界定。因?JTA 不像 JDBC 那样有名Q所以我们首先做一个简介?/p>



回页?/font>


JTA?/font>

Java 事务 API(JTA) 及其同门兄弟 Java 事务服务(Java Transaction Service JTS)?J2EE q_提供了分布式事务服务。一?分布式的事务涉及一个事务管理器和一个或者多个资源管理器。一?资源理?/i>是Q何类型的持久性的数据存储。事务管理器负责协调所有事务参与者之间的通信。事务管理器与资源管理器之间的关pd?2 所C:


?2. 一个事务管理器和资源管理器
一个事务管理器和资源管理器

JTA 事务?JDBC 事务功能更强。JDBC 事务局限ؓ一个数据库q接Q?JTA 事务可以有多个参与者。所有下?Java q_lg都可以参?JTA 事务Q?/p>

  • JDBC q接
  • JDO PersistenceManager 对象
  • JMS 队列
  • JMS 主题
  • 企业 JavaBeans
  • W合 J2EE q接体系l构(J2EE Connector Architecture)规范的资源适配?




回页?/font>


使用 JTA 的事务界?/font>

要用 JTA q行事务界定Q应用程序要调用 javax.transaction.UserTransaction 接口中的Ҏ。清?4 昄了对 UserTransaction 对象的典?JNDI 查询Q?


清单 4. 一个对 UserTransaction 对象?JDNI 查询
												
														      import javax.transaction.*;
      import javax.naming.*;
      // ...
      InitialContext ctx = new InitialContext();
      Object txObj = ctx.lookup("java:comp/UserTransaction");
      UserTransaction utx = (UserTransaction) txObj;


												
										

当应用程序找C UserTransaction 对象后,可以开始事务了Q如清单 5 所C:


清单 5. ?JTA 开始一个事?/b>
												
														      utx.begin();
      // ...
      DataSource ds = obtainXADataSource();
      Connection conn = ds.getConnection();
      pstmt = conn.prepareStatement("UPDATE MOVIES ...");
      pstmt.setString(1, "Spinal Tap");
      pstmt.executeUpdate();
      // ...
      utx.commit();
      // ...


												
										

当应用程序调?commit() Ӟ事务理器用一个两阶段的提交协议结束事务?





回页?/font>


控制事务?JTA Ҏ

javax.transaction.UserTransaction 接口提供了以下事务控制方法:

  • public void begin()
  • public void commit()
  • public void rollback()
  • public int getStatus()
  • public void setRollbackOnly()
  • public void setTransactionTimeout(int)

应用E序调用 begin() 开始事务。应用程序调?commit() 或?rollback() l束事务。参?参考资?/font>以了解更多关于用 JTA q行事务理的内宏V?





回页?/font>


使用 JTA ?JDBC

开发h员通常?DAO cM?JDBC q行底层数据操作。如果计划用 JTA 界定事务Q那么就需要有一个实?javax.sql.XADataSource ?javax.sql.XAConnection ?javax.sql.XAResource 接口?JDBC 驱动E序。一个实Cq些接口的驱动程序将可以参与 JTA 事务。一?XADataSource 对象是一?XAConnection 对象的工厂?XAConnection s 是参?JTA 事务?JDBC q接?

您将需要用应用服务器的理工具讄 XADataSource 。从应用服务器和 JDBC 驱动E序的文档中可以了解到相关的指导?

J2EE 应用E序?JNDI 查询数据源。一旦应用程序找C数据源对象,它就调用 javax.sql.DataSource.getConnection() 以获得到数据库的q接?

XA q接与非 XA q接不同。一定要C XA q接参与?JTA 事务。这意味着 XA q接不支?JDBC 的自动提交功能。同Ӟ应用E序一定不要对 XA q接调用 java.sql.Connection.commit() 或?java.sql.Connection.rollback() 。相反,应用E序应该使用 UserTransaction.begin()?/code>UserTransaction.commit() ?serTransaction.rollback() ?





回页?/font>


选择最好的方式

我们讨论了如何用 JDBC ?JTA 界定事务。每一U方式都有其优点Q您需要决定哪一U最适合于您的应用程序?/p>

在最q的许多目中,我们组是用 JDBC API q事务界定来构徏 DAO cȝ。这?DAO cd以ȝ如下Q?/p>

  • 事务界定代码嵌入?DAO cM?
  • DAO cM?JDBC API q行事务界定?
  • 调用者不能界定事务?
  • 事务范围局限于单个 JDBC q接?

JDBC 事务q不L适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库Q那么下列实现策略也许更合适:

  • 事务?JTA 界定?
  • 事务界定代码?DAO 中分d来?
  • 调用者负责界定事务?
  • DAO 加入一个全局事务?

JDBC 方式׃其简单性而具有吸引力QJTA 方式提供了更大的灉|性。您所选择的实现将取决于应用程序的特定需求?/p>



回页?/font>


日志记录?DAO

一个良好实现的 DAO cd使用日志记录来捕捉有兛_q行时行为的l节。您可以选择记录异常、配|信息、连接状态、JDBC 驱动E序元数据、或者查询参数。日志对于开发的所有阶D都很有用。我l常在开发时、测试时和生产中分析应用E序日志?/p>

在本节,我将展示一个显C如何将 Jakarta Commons Logging 加入?DAO 中的代码CZ。在q之前,让我们回一下一些基本知识?/p>

选择日志?/font>

许多开发h员用一U原始格式进行日志记录: System.out.println ?System.err.println ?Println 语句速度快且使用方便Q但是它们没有提供全功能的日志记录系l所h的功能。表 2 列出?Java q_的日志库Q?

?2. Java q_的日志库

日志?/strong> 开放源代码Q?/b> URL
java.util.logging 不是 http://java.sun.com/j2se/
Jakarta Log4j ?/td> http://jakarta.apache.org/log4j/
Jakarta Commons Logging ?/td> http://jakarta.apache.org/commons/logging.html

Jakarta Commons Logging 可以?java.util.logging 或?Jakarta Log4j 一同用。Commons Logging 是一个日志抽象层Q它隔离了应用程序与底层日志实现。?Commons LoggingQ您可以通过改变配置文g更换底层日志实现。Commons Logging ?Jakarta Struts 1.1 ?Jakarta HttpClient 2.0 中用?

一个日志记录示?/font>

清单 7 昄了如何在 DAO cM使用 Jakarta Commons LoggingQ?/p>
清单 7. DAO cM?Jakarta Commons Logging
												
														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 ...
	}
      }
}

												
										

日志记录是所有Q务关键型应用E序的重要部分。如果在 DAO 中遇到故障,那么日志通常可以提供判断出错位置的最好信息。将日志加入?DAO 可以保证您有Zq行调试和故障排除?/p>



回页?/font>


DAO 中的异常处理

我们讨论q了事务界定和日志,现在对于如何在数据访问对象上应用它们有了更深入的理解。我们的W三个和最后一个讨题是异常处理。遵从几个简单的异常处理指导可以使您?DAO 更容易用、更健壮及更易于l护?/p>

在实?DAO 模式Ӟ考虑以下问题Q?/p>

  • DAO 的公共接口中的方法是否抛出检查过的异常?
  • 如果是的话,抛出何种查过的异常?
  • ?DAO 实现cM如何处理异常Q?

在?DAO 模式的过E中Q我们的组开发了一些处理异常的原则。遵从这些原则可以极大地改进您的 DAOQ?/p>

  • DAO Ҏ应该抛出有意义的异常?
  • DAO Ҏ不应该抛?java.lang.Exception ?java.lang.Exception 太一般化了。它不传递关于底层问题的M信息?
  • DAO Ҏ不应该抛?java.sql.SQLException 。SQLException 是一个低U别?JDBC 异常。一?DAO 应该力争装 JDBC 而不是将 JDBC 公开l应用程序的其余部分?
  • 只有在可以合理地预期调用者可以处理异常时QDAO 接口中的Ҏ才应该抛出检查过的异常。如果调用者不能以有意义的方式处理q个异常Q那么考虑抛出一个未查的(q行?异常?
  • 如果数据讉K代码捕获了一个异常,不要忽略它。忽略捕L异常?DAO 是很难进行故障诊断的?
  • 使用链接的异常将低别的异常转化为高U别的异常?
  • 考虑定义标准 DAO 异常cRSpring Framework (参阅 参考资?/font>)提供了很好的一套预定义?DAO 异常cR?

有关异常和异常处理技术的更多信息参阅 参考资?/font>?





回页?/font>


实现实例Q?MovieDAO

MovieDAO 是一个展C本文中讨论的所有技术的 DAOQ事务界定、日志和异常处理。您可以?参考资?/font>一节中扑ֈ MovieDAO 源代码。代码分Z个包Q?

  • daoexamples.exception
  • daoexamples.movie
  • daoexamples.moviedemo

DAO 模式的这个实现包含下面列出的cd接口Q?/p>

  • daoexamples.movie.MovieDAOFactory
  • daoexamples.movie.MovieDAO
  • daoexamples.movie.MovieDAOImpl
  • daoexamples.movie.MovieDAOImplJTA
  • daoexamples.movie.Movie
  • daoexamples.movie.MovieImpl
  • daoexamples.movie.MovieNotFoundException
  • daoexamples.movie.MovieUtil

MovieDAO 接口定义?DAO 的数据操作。这个接口有五个ҎQ如下所C:

  • public Movie findMovieById(String id)
  • public java.util.Collection findMoviesByYear(String year)
  • public void deleteMovie(String id)
  • public Movie createMovie(String rating, String year, String, title)
  • public void updateMovie(String id, String rating, String year, String title)

daoexamples.movie 包包?MovieDAO 接口的两个实现。每一个实C用一U不同的方式q行事务界定Q如?3 所C:

?3. MovieDAO 实现

MovieDAOImpl MovieDAOImplJTA
实现 MovieDAO 接口? ?/td> ?/td>
通过 JNDI 获得 DataSourceQ?/td> ?/td> ?/td>
?DataSource 获得 java.sql.Connection 对象Q?/td> ?/td> ?/td>
DAO 在内部界定事务? ?/td> ?/td>
使用 JDBC 事务Q?/td> ?/td> ?/td>
使用一?XA DataSourceQ?/td> ?/td> ?/td>
参与 JTA 事务Q?/td> ?/td> ?/td>

MovieDAO 演示应用E序

q个演示应用E序是一个名?daoexamples.moviedemo.DemoServlet ?servlet cR?DemoServlet 使用q两?Movie DAO 查询和更新表中的电媄数据?

q个 servlet 展示了如何将支持 JTA ?MovieDAO ?Java 消息服务(Java Message Service)l合C个事务中Q如清单 8 所C?


清单 8. ?MovieDAO ?JMS 代码l合C个事务中
												
															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();

												
										


rendong 2006-08-31 23:16 发表评论
]]>权限QDAOhttp://www.tkk7.com/rendong/archive/2006/08/31/66954.htmlrendongrendongThu, 31 Aug 2006 14:36:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/31/66954.htmlhttp://www.tkk7.com/rendong/comments/66954.htmlhttp://www.tkk7.com/rendong/archive/2006/08/31/66954.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/66954.htmlhttp://www.tkk7.com/rendong/services/trackbacks/66954.html 当前位置: 首页 >> 数据?>> Oracle >> 我的权限控制(JBX + struts + hibernate + ORACLE)
 
我的权限控制(JBX + struts + hibernate + ORACLE) 

--------------------------------------------------------------------------------
 
作者::     来源Q   ?发表旉Q?006-06-08     览ơ数Q?8    字号Q大  中??
  
通过qo器判断用h?
W一?建立UserPermissionFilterc?


import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

import test.system.SysUserApi;
import test.vo.SysUserVO;
import test.system.dao.SysUserDao;
import test.Const;

public class UserPermissionFilter extends HttpServlet implements Filter {

  protected FilterConfig filterConfig = null;

  public void destroy() {
    this.filterConfig = null;
  }


  public void doFilter(
      ServletRequest request,
      ServletResponse response,
      FilterChain filterChain) throws IOException, ServletException {
    try {
      HttpServletRequest req = (HttpServletRequest) request;
      SysUserVO userSession = new SysUserVO();
      userSession = (SysUserVO)req.getSession().getAttribute(Const.SESSION_USER);
      if (userSession == null) {
        HttpServletResponse rep = (HttpServletResponse) response;

        rep.sendRedirect("/admin/login.jsp");
             }else{
        filterChain.doFilter(request, response);
      }
    }
    catch (Exception e) {}
  }
  public void init(FilterConfig filterConfig) throws ServletException {
    this.filterConfig = filterConfig;
  }
  public FilterConfig getFilterConfig() {
    return filterConfig;
  }

  public void setFilterConfig(FilterConfig filterConfig) {
    this.filterConfig = filterConfig;
  }

}


W二?配置WEB.xml文g
讄qo?
  <filter>
    <filter-name>userpermission</filter-name>
    <filter-class>sports.tools.UserPermissionFilter</filter-class>
  </filter>
讄qo器映?因ؓqo器不能过滤全部的E序,所以可以用列表的Ş式来增加需要过滤的文g.如下.一个过滤器可以qo多个映射文g.
  <filter-mapping>
    <filter-name>userpermission</filter-name>
    <url-pattern>/admin/index.jsp</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>userpermission</filter-name>
    <url-pattern>/admin/edit/*</url-pattern>
  </filter-mapping>
 
 
 
======================================
http://www.itwenzhai.com/data/2006/0608/article_22958.htm
=========================================
http://www.itwenzhai.com/data/2006/0626/article_25178.htm
=========================================


  不重复DAO
===============

 

׃ Java?5 泛型的采用,有关泛型cd安全 Data Access Object (DAO) 实现的想法变得切实可行。在本文中,pȝ架构?Per Mellqvist 展示了基?Hibernate 的泛?DAO 实现cR然后展C如何?Spring AOP introductions 类型安全接口添加到cM以便于查询执行?br />对于大多数开发h员,为系l中的每?DAO ~写几乎相同的代码到目前为止已经成ؓ一U习惯。虽然所有h都将q种重复标识?“代码味道”,但我们大多数都已l学会忍受它。其实有解决Ҏ。可以用许?ORM 工具来避免代码重复。例如,使用 HibernateQ您可以单地为所有的持久域对象直接用会话操作。这U方法的~点是损׃cd安全?/p>

Z么您要ؓ数据讉K代码提供cd安全接口Q我会争辩说Q当它与C IDE 工具一起用时Q会减少~程错误q提高生产率。首先,cd安全接口清楚地指明哪些域对象h可用的持久存储。其ơ,它消除了易出错的cd强制转换的需要(q是一个在查询操作中比?CRUD 中更常见的问题)。最后,它有效利用了今天大多?IDE 具备的自动完成特性。用自动完成是C什么查询可用于特定域类的快h法?/p>

在本文中Q我ؓ您展C如何避免再三地重复 DAO 代码Q而仍保留cd安全接口的优炏V事实上Q您需要ؓ每个?DAO ~写的只?Hibernate 映射文g、无格式?Java 接口以及 Spring 配置文g中的 10 行?/p>

DAO 实现

DAO 模式对Q何企?Java 开发h员来说都应该很熟悉。但是模式的实现各不相同Q所以我们来澄清一下本文提供的 DAO 实现背后的假设:

pȝ中的所有数据库讉K都通过 DAO q行以实现封装?
每个 DAO 实例负责一个主要域对象或实体。如果域对象h独立生命周期Q它应具有自q DAO?
DAO 负责域对象的创徏、读取(按主键)、更新和删除Qcreations, reads, updates, and deletionsQCRUDQ?
DAO 可允许基于除主键之外的标准进行查询。我之UCؓ查找器方?或查扑֙。查扑֙的返回值通常?DAO 负责的域对象集合?
DAO 不负责处理事务、会话或q接。这些不?DAO 处理是ؓ了实现灵zL?
泛型 DAO 接口

泛型 DAO 的基是其 CRUD 操作。下面的接口定义泛型 DAO 的方法:


清单 1. 泛型 DAO 接口
public interface GenericDao <T, PK extends Serializable> {

    /** Persist the newInstance object into database */
    PK create(T newInstance);

    /** Retrieve an object that was previously persisted to the database using
     *   the indicated id as primary key
     */
    T read(PK id);

    /** Save changes made to a persistent object.  */
    void update(T transientObject);

    /** Remove an object from persistent storage in the database */
    void delete(T persistentObject);
}

 


实现接口

?Hibernate 实现清单 1 中的接口十分单,如清?2 所C。它只需调用底层 Hibernate Ҏ和添加强制类型{换。Spring 负责会话和事务管理。(当然Q我假设q些函数已做了适当的设|,但该主题?Hibernate ?Springt 手册中有详细介绍。)


清单 2. W一个泛?DAO 实现
public class GenericDaoHibernateImpl <T, PK extends Serializable>
    implements GenericDao<T, PK>, FinderExecutor {
    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> type) {
        this.type = type;
    }

    public PK create(T o) {
        return (PK) getSession().save(o);
    }

    public T read(PK id) {
        return (T) getSession().get(type, id);
    }

    public void update(T o) {
        getSession().update(o);
    }

    public void delete(T o) {
        getSession().delete(o);
    }

    // Not showing implementations of getSession() and setSessionFactory()
            }
 


Spring 配置

最后,?Spring 配置中,我创Z GenericDaoHibernateImpl 的一个实例。必d?GenericDaoHibernateImpl 的构造函?DAO 实例负责哪个域cR只有这PHibernate 才能在运行时知道?DAO 理的对象类型。在清单 3 中,我将域类 Person 从示例应用程序传递给构造函敎ͼq将先前配置?Hibernate 会话工厂讄为已实例化的 DAO 的参敎ͼ


清单 3. 配置 DAO
<bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl">
        <constructor-arg>
            <value>genericdaotest.domain.Person</value>
        </constructor-arg>
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
</bean>
        
2?br />我还没有完成Q但我所完成的确实已l可以用了。在清单 4 中,可以看到原封不动使用该泛?DAO 的示例:


清单 4. 使用 DAO
public void someMethodCreatingAPerson() {
    ...
    GenericDao dao = (GenericDao)
     beanFactory.getBean("personDao"); // This should normally be injected

    Person p = new Person("Per", 90);
    dao.create(p);
}
        

 

现在Q我有一个能够进行类型安?CRUD 操作的泛?DAO。让子类 GenericDaoHibernateImpl 为每个域对象d查询能力非常合理。因为本文的目的在于展示如何不ؓ每个查询~写昑ּ?Java 代码来实现查询,但是Q我用其他两个工具将查询引入 DAOQ也是 Spring AOP ?Hibernate 命名的查询?/p>

Spring AOP introductions

可以使用 Spring AOP 中的 introductions 功能添加到现有对象Q方法是功能包装在代理中,定义应实现的接口Qƈ所有先前未支持的方法指zֈ单个处理E序。在我的 DAO 实现中,我?introductions 许多查扑֙Ҏd到现有泛?DAO cM。因为查扑֙Ҏ是特定于每个域对象的Q因此将其应用于泛型 DAO 的类型化接口?/p>

Spring 配置如清?5 所C:


清单 5. FinderIntroductionAdvisor ?Spring 配置
<bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/>

<bean id="abstractDaoTarget"
        class="genericdao.impl.GenericDaoHibernateImpl" abstract="true">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
</bean>

<bean id="abstractDao"
        class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
        <property name="interceptorNames">
            <list>
                <value>finderIntroductionAdvisor</value>
            </list>
        </property>
</bean>
        

 

在清?5 的配|文件中Q我定义了三?Spring bean。第一?bean ?FinderIntroductionAdvisorQ它处理引入?DAO 的所有方法,q些Ҏ?GenericDaoHibernateImpl cM不可用。我E后详l介l?Advisor bean?/p>

W二?bean ?“抽象的”。在 Spring 中,q意味着?bean 可在其他 bean 定义中被重用Q但不被实例化。除了抽象特性之外,?bean 定义只指出我惌 GenericDaoHibernateImpl 的实例以及该实例需要对 SessionFactory 的引用。注意,GenericDaoHibernateImpl cM定义一个构造函敎ͼ该构造函数接受域cM为其参数。因 bean 定义是抽象的Q所以我来可以无数ơ地重用该定义,q将构造函数参数设|ؓ合适的域类?/p>

最后,W三个也是最有趣?bean ?GenericDaoHibernateImpl ?vanilla 实例包装在代理中Q赋予其执行查找器方法的能力。该 bean 定义也是抽象的,不指定希望引入到 vanilla DAO 的接口。该接口对于每个具体的实例是不同的。注意,清单 5 昄的整个配|仅定义一ơ?/p>

3?/p>

扩展 GenericDAO

当然Q每?DAO 的接口都Z GenericDao 接口。我只需使该接口适应特定的域cdƈ扩展该接口以包括查找器方法。在清单 6 中,可以看到为特定目的扩展的 GenericDao 接口CZQ?/p>


清单 6. PersonDao 接口
public interface PersonDao extends GenericDao<Person, Long> {
    List<Person> findByName(String name);
}

 

 

很明显,清单 6 中定义的Ҏ旨在按名U查?Person。必需?Java 实现代码全部是泛型代码,在添加更?DAO 时不需要Q何更新?/p>

配置 PersonDao

因ؓ Spring 配置依赖于先前定义的 “抽象?beanQ因此它变得相当z。我需要指?DAO 负责哪个域类Qƈ且需要告?Springs ?DAO 应实现哪个接口(一些方法是直接使用Q一些方法则是通过使用 introductions 来用)。清?7 展示?PersonDAO ?Spring 配置文gQ?/p>


清单 7. PersonDao ?Spring 配置
<bean id="personDao" parent="abstractDao">
    <property name="proxyInterfaces">
        <value>genericdaotest.dao.PersonDao</value>
    </property>
    <property name="target">
        <bean parent="abstractDaoTarget">
            <constructor-arg>
                <value>genericdaotest.domain.Person</value>
            </constructor-arg>
        </bean>
    </property>
</bean>
        

 

在清?8 中,可以看到使用了这个更新后?DAO 版本Q?/p>


清单 8. 使用cd安全接口
public void someMethodCreatingAPerson() {
    ...
    PersonDao dao = (PersonDao)
     beanFactory.getBean("personDao"); // This should normally be injected

    Person p = new Person("Per", 90);
    dao.create(p);

    List<Person> result = dao.findByName("Per"); // Runtime exception
}
        

 

虽然清单 8 中的代码是用类型安?PersonDao 接口的正方法,?DAO 的实现ƈ不完整。调?findByName() 会导致运行时异常。问题在于我q没有实现调?findByName() 所必需的查询。剩下要做的是指定查询。ؓ更正该问题,我用了 Hibernate 命名查询?/p>


 

Hibernate 命名查询

使用 HibernateQ可以在 Hibernate 映射文g (hbm.xml) 中定?HQL 查询qؓ其命名。稍后可以通过单地引用l定名称来在 Java 代码中用该查询。该Ҏ的优点之一是能够在部v时优化查询,而无需更改代码。您一会将会看刎ͼ另一个优Ҏ无需~写M?Java 实现代码Q就可以实现 “完整的?DAO。清?9 是带有命名查询的映射文g的示例:


清单 9. 带有命名查询的映文?br /> <hibernate-mapping package="genericdaotest.domain">
     <class name="Person">
         <id name="id">
             <generator class="native"/>
         </id>
         <property name="name" />
         <property name="weight" />
     </class>

     <query name="Person.findByName">
         <![CDATA[select p from Person p where p.name = ? ]]>
     </query>
 </hibernate-mapping>
        

 

清单 9 定义了域c?Person ?Hibernate 映射Q该域类h两个属性:name ?weight。Person 是具有上q属性的?POJO。该文gq包含一个在数据库中查找 Person 所有实例的查询Q其?“name?{于提供的参数。Hibernate 不ؓ命名查询提供M真正的名U空间功能。出于讨论目的,我ؓ所有查询名U都加了域类的短Q非限定Q名UC为前~。在现实世界中,使用包括包名U的完全cd可能是更好的L?/p>


 

逐步概述

您已l看CZQ何域对象创徏和配|新 DAO 所必需的全部步骤。三个简单的步骤是:

定义一个接口,它扩?GenericDao q包含所需的Q何查扑֙Ҏ?
每个查扑֙的命名查询添加到域对象的 hbm.xml 映射文g?
?DAO d 10 ?Spring 配置文g?
查看执行查找器方法的代码Q只~写了一ơ!Q来l束我的讨论?/p>

4?/p>

可重用的 DAO c?/p>

使用?Spring advisor ?interceptor 很简单,事实上它们的工作是向后引?GenericDaoHibernateImplClass。方法名?“find?打头的所有调用都传递给 DAO 和单个方?executeFinder()?/p>


清单 10. FinderIntroductionAdvisor 的实?br />public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {
    public FinderIntroductionAdvisor() {
        super(new FinderIntroductionInterceptor());
    }
}

public class FinderIntroductionInterceptor implements IntroductionInterceptor {

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();

        String methodName = methodInvocation.getMethod().getName();
        if (methodName.startsWith("find")) {
            Object[] arguments = methodInvocation.getArguments();
            return genericDao.executeFinder(methodInvocation.getMethod(), arguments);
        } else {
            return methodInvocation.proceed();
        }
    }

    public boolean implementsInterface(Class intf) {
        return intf.isInterface() && FinderExecutor.class.isAssignableFrom(intf);
    }
}
 

 

executeFinder() Ҏ

清单 10 的实C惟一~少的是 executeFinder() 实现。该代码查看调用的类和方法的名称Qƈ使用配置上的U定其?Hibernate 查询的名U相匚w。还可以使用 FinderNamingStrategy 来支持其他命名查询的Ҏ。默认实现查扑֏?“ClassName.methodName?的查询,其中 ClassName 是不带包的短名称。清?11 完成了泛型类型安?DAO 实现Q?


清单 11. executeFinder() 的实?br />public List<T> executeFinder(Method method, final Object[] queryArgs) {
     final String queryName = queryNameFromMethod(method);
     final Query namedQuery = getSession().getNamedQuery(queryName);
     String[] namedParameters = namedQuery.getNamedParameters();
     for(int i = 0; i < queryArgs.length; i++) {
             Object arg = queryArgs[i];
             Type argType =  namedQuery.setParameter(i, arg);
      }
      return (List<T>) namedQuery.list();
 }

 public String queryNameFromMethod(Method finderMethod) {
     return type.getSimpleName() + "." + finderMethod.getName();
 }
 

 

l束?/p>

?Java 5 之前Q该语言不支持编写既cd安全?泛型的代码,您必d能选择其中之一。在本文中,您已l看C个结合?Java 5 泛型?Spring ?HibernateQ以?AOPQ等工具来提高生产率的示例。泛型类型安?DAO cȝ当容易编?—?您只需要单个接口、一些命名查询和?Spring 配置d?10 行代?—?而且可以极大地减错误ƈ节省旉?/p>

几乎本文的所有代码都是可重用的。尽您?DAO cd能包含此处没有实现的查询和操作类型(比如Q批操作Q,但用我所展示的技术,您至应该能够实现其中的一部分。参?参考资?了解其他泛型cd安全 DAO cd现?/p>

致谢

?Java 语言中出现泛型以来,单个泛型cd安全 DAO 的概念已l成Z题。我曑֜ JavaOne 2004 中与 Don Smith 要讨Z泛型 DAO 的灵zL。本文用的 DAO 实现cL在作为示例实玎ͼ实际上还存在其他实现。例如,Christian Bauer 已经发布了带?CRUD 操作和标准搜索的实现QEric Burke 也在该领域做Z工作。我信会有更多的实现出现。我要额外感?ChristianQ他目睹了我~写泛型cd安全 DAO 的第一ơ尝试ƈ提出改进。最后,我要感谢 Ramnivas Laddad 的无价帮助,他审阅了本文?/p>

 



rendong 2006-08-31 22:36 发表评论
]]>
Spring+Hibernate+Struts配置(转蝲 http://www.tkk7.com/envoydada/archive/2006/07/24/45438.html)http://www.tkk7.com/rendong/archive/2006/08/01/61208.htmlrendongrendongTue, 01 Aug 2006 07:06:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/01/61208.htmlhttp://www.tkk7.com/rendong/comments/61208.htmlhttp://www.tkk7.com/rendong/archive/2006/08/01/61208.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61208.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61208.html阅读全文

rendong 2006-08-01 15:06 发表评论
]]>
l合struts和hibernate谈J2EE架构的数据表C[转蝲]http://www.tkk7.com/rendong/archive/2006/08/01/61185.htmlrendongrendongTue, 01 Aug 2006 05:49:00 GMThttp://www.tkk7.com/rendong/archive/2006/08/01/61185.htmlhttp://www.tkk7.com/rendong/comments/61185.htmlhttp://www.tkk7.com/rendong/archive/2006/08/01/61185.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/61185.htmlhttp://www.tkk7.com/rendong/services/trackbacks/61185.html ?struts+ hibernate q种l构中,是不应该把Hibernate产生的PO直接传递给JSP的,不管他是IteratorQ还是ListQ这是一个设计错误?

我来谈谈在J2EE架构中各层的数据表示ҎQ?

Web层的数据表示是FormBeanQ数据来源于HTML Form POST
业务层的数据表示是VO
持久层的数据表示是POQ其数据来源于数据库Q持久层的数据表CZ如CMP

在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内Q而不应该扩散到其它层Q这样可以降低层间的耦合性,提高J2EE架构整体的可l护性和可扩展性。比如说Web层的逻辑q行了修改,那么只需要修改FormBean的结构,而不需要触动业务层和持久层的代码修攏V同hQ当数据库表q行了小的调_那么也只需要修Ҏ久层数据表示Q而不需要触动业务层代码和Web层代码?

不过׃Hibernate的强大功能,例如动态生成POQPO的状态管理可以脱SessionQ得在应用了Hibernate的J2EE框架中,PO完全可以充当VOQ因此我们下面把PO和VO合ƈQ统UCؓPO?

先来谈谈ActionFormBean和持久层的PO之间的重大区别?

在简单的应用中,ActionFormBean和PO几乎是没有区别,所以很多hq脆是用ActionFormBean来充当POQ于是ActionFormBean从JSP面到Servlet控制层再C务层Q然后穿q持久层Q最后一直映到数据库表。真是一竿子捅到了底Q?

但是在复杂的应用中,ActionFormBean和PO是分ȝQ他们也不可能一栗ActionFormBean是和|页里面的Form表单一一对应的,Form里面有什么元素,Bean里面有什么属性。而PO和数据库表对应,因此如果数据库表不修改,那么PO也不会修改,如果面的流E和数据库表字段对应关系不一_那么你又如何能够使用ActionFormBean来取代PO呢?

比如说吧Q用h册页面要求注册用L基本信息Q因此HTML Form里面包含了基本信息属性,于是你需要一个ActionFormBean来一一对应(注意Q是一一对应)Q每个Bean属性对应一个文本框或者选择框什么的?

而用戯个持久对象呢Q他的属性和ActionFormBean有什么明显不同呢Q他会有一些ActionFormBean所没有的集合属性,比如说用L权限属性,用户的组属性,用户的帖子等{。另外还有可能的是在ActionFormBean里面?个属性,分别是用LFirst Name, Middle Name, Last NameQ而在我的Userq个持久对象中就是一?Name 对象属性?

假设我的注册面原来只要你提供First NameQ那么ActionFormBeanp一个属性,后来我要你提供全名,你要改ActionFormBeanQ加两个属性。但是这个时候PO是不应该修改_因ؓ数据库没有改?

那么在一个完整的J2EEpȝ中应该如何进行合理的设计呢?

JSP(View) ---> ActionFormBean(Module) ---> Action(Control)

ActionFormBean是Web层的数据表示Q它和HTML面Form对应Q只要Web面的操作流E发生改变,它就要相应的q行修改Q它不应该也不能被传递到业务层和持久层,否则一旦页面修改,会一直牵q到业务层和持久层的大面U的代码q行修改Q对于Y件的可维护性和可扩展性而言Q是一个灾难,Actiont是他的边界Q到此ؓ止!

Action(Web Control) ---> Business Bean ---> DAO ---> ORM --->DB

而PO则是业务层和持久层的数据表示Q它在业务层和持久层之间q行动Q他不应该也不能被传递到Web层的View中去Q而ActionServlet是他的边界Q到此ؓ止!

然后来看一看整个架构的程Q?

当用户通过览器访问网,提交了一个页面。于是Action拿到了这个FormBeanQ他会把FormBean属性读出来Q然后构造一个PO对象Q再调用业务层的Beanc,完成了注册操作,重定向到成功面。而业务层Bean收到q个PO对象之后Q调用DAO接口ҎQ进行持久对象的持久化操作?

当用h询某个会员的信息的时候,他用全名q行查询Q于是Action得到一个UserNameFormBean包括?个属性,分别是first name, middle name, last nameQ然后Action把UserNameFormBean?个属性读出来Q构造Name对象Q再调用业务BeanQ把Name对象传递给业务BeanQ进行查询?

业务Bean取得Name(注意: Name对象只是User的一个属?对象之后调用DAO接口Q返回一个User的PO对象Q注意这个User不同于在Web层用的UserFormBeanQ他有很多集合属性滴。然后业务Bean把User对象q回lAction?

Action拿到User之后Q把User的基本属性取?集合属性如果不需要就免了)Q构造UserFormBeanQ然后把UserFormBean request.setAttribute(...)Q然后重定向到查询结果页面?

查询面拿到request对象里面的ActionFormBeanQ自动调用tag昄之?

ȝQ?

FormBean是Web层的数据表示Q他不能被传递到业务层;PO是持久层的数据表C,在特定情况下Q例如Hibernate中,他可以取代VO出现在业务层Q但是不POq是VO都必限制在业务层内使用Q最多到达Web层的ControlQ绝不能被扩散到View厅R?

FormBean和PO之间的数据{化是在Action中进行滴?

BTW:

JDO1.xq不能像Hibernate功能q样强大QPO不能q持久层,所以必d业务层用VOQ因此必d业务层进行大量的VO和PO的{化操作,相对于Hibernate来说Q编E比较烦琐?

当然咯,理论是一回事Q实际操作也不一定非要这样干Q你可以自行取舍Q在实际目中灵zM点,增加一点bad smellQ提高开发效率。只不过在大型项目中最好还是严丝合~,不然的话Q改版的时候会痛苦的很滴?/span>



rendong 2006-08-01 13:49 发表评论
]]>Struts+Spring+Hibernate实现上传下蝲(转蝲自http://www.tkk7.com/ltc603/archive/2006/01/13/27966.html)http://www.tkk7.com/rendong/archive/2006/07/31/60977.htmlrendongrendongMon, 31 Jul 2006 03:23:00 GMThttp://www.tkk7.com/rendong/archive/2006/07/31/60977.htmlhttp://www.tkk7.com/rendong/comments/60977.htmlhttp://www.tkk7.com/rendong/archive/2006/07/31/60977.html#Feedback0http://www.tkk7.com/rendong/comments/commentRss/60977.htmlhttp://www.tkk7.com/rendong/services/trackbacks/60977.html (转蝲?a href="/ltc603/archive/2006/01/13/27966.html">http://www.tkk7.com/ltc603/archive/2006/01/13/27966.html)
引言

  文g的上传和下蝲在J2EE~程已经是一个非常古老的话题了,也许您马上就能掰着指头数出好几个著名的大gQ如SmartUpload、Apache的FileUpload。但如果您的目是构建在Struts+Spring+HibernateQ以下称SSHQ框架上的,q些大g显得笨重而桑了QSSH提供了一个简h便的文g上传下蝲的方案,我们只需要通过一些配|ƈ辅以量的代码就可以完好解决q个问题了?br />
  本文围lSSH文g上传下蝲的主题,向您详细讲述如何开发基于SSH的WebE序。SSH各框架的均ؓ当前最新版本:

  ·Struts 1.2

  ·Spring 1.2.5

  ·Hibernate 3.0

  本文选用的数据库为Oracle 9iQ当然你可以在不改动代码的情况下Q通过配置文g的调整将其移植到MhBlob字段cd的数据库上,如MySQLQSQLServer{?br />
  M实现

  上传文g保存到T_FILE表中QT_FILE表结构如下:


?1 T_FILE表结?/div>

  其中Q?br />
  ·FILE_IDQ文件IDQ?2个字W,用Hibernate的uuid.hex法生成?br />
  ·FILE_NAMEQ文件名?br />
  ·FILE_CONTENTQ文件内容,对应Oracle的Blobcd?br />
  ·REMARKQ文件备注?br />
  文g数据存储在Blobcd的FILE_CONTENT表字D上Q在Spring中采用OracleLobHandler来处理Lob字段Q包括Clob和BlobQ,׃在程序中不需要引用到oracle数据驱动E序的具体类且屏蔽了不同数据库处理Lob字段Ҏ上的差别Q从而撤除程序在多数据库UL上的樊篱?

  1Q首先数据表中的Blob字段在Java领域对象中声明ؓbyte[]cdQ而非java.sql.Blobcd?br />
  2Q数据表Blob字段在Hibernate持久化映文件中的type为org.springframework.orm.hibernate3.support.BlobByteArrayTypeQ即Spring所提供的用戯定义的类型,而非java.sql.Blob?

  3Q在Spring中用org.springframework.jdbc.support.lob.OracleLobHandler处理Oracle数据库的Blobcd字段?br />
  通过q样的设|和配置Q我们就可以象持久化表的一般字D늱型一样处理Blob字段了?br />
  以上是SpringQHibernate文件二q制数据持久化到数据库的解决ҎQ而Struts通过表单中filecd的组件映ؓActionForm中类型ؓorg.apache.struts.upload. FormFile的属性来获取表单提交的文件数据?br />
  lg所qͼ我们可以通过?2Q描l出SSH处理文g上传的方案:


?2 SSH处理文g上传技术方?/div>

  文g上传的页面如?3所C:


?3 文g上传面

  文g下蝲的页面如?4所C:


?4 文g下蝲面

  该工E的资源l构如图 5所C:


?5 工程资源l构

  工程的类按SSH的层ơ结构划分ؓ数据持久层、业务层和Web层;WEB-INF下的applicationContext.xml为Spring的配|文Ӟstruts-config.xml为Struts的配|文Ӟfile-upload.jsp为文件上传页面,file-list.jsp为文件列表页面?br />
  本文后面的章节将从数据持久层-Q业务层-QWeb层的开发顺序,逐层讲解文g上传下蝲的开发过E?br />
  数据持久?/b>

  1、领域对象及映射文g

  您可以用Hibernate Middlegen、HIbernate Tools、Hibernate Syhchronizer{工h手工的方式,~写Hibernate的领域对象和映射文g。其中对应T_FILE表的领域对象Tfile.java为:

  代码 1 领域对象Tfile

1. package sshfile.model;
2. public class Tfile
3.{
4. private String fileId;
5. private String fileName;
6. private byte[] fileContent;
7. private String remark;
8. ?/getter and setter
9. }

  特别需要注意的是:数据库表为Blobcd的字D在Tfile中的fileContentcd为byte[]。Tfile的Hibernate映射文gTfile.hbm.xml攑֜Tfile .javacL件的相同目录下:

  代码 2 领域对象映射文g

1. Q?xml version="1.0"?Q?br />2. Q?DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" Q?br />5. Qhibernate-mappingQ?br />6. Qclass name="sshfile.model.Tfile" table="T_FILE"Q?br />7. Qid name="fileId" type="java.lang.String" column="FILE_ID"Q?br />8. Qgenerator class="uuid.hex"/Q?br />9. Q?idQ?br />10. Qproperty name="fileContent"
11. type="org.springframework.orm.hibernate3.support.BlobByteArrayType"
12. column="FILE_CONTENT" lazy="true"/Q?br />13. ?/其它一般字D늚映射
14. Q?classQ?br />15. Q?hibernate-mappingQ?/td>

  fileContent字段映射为Spring所提供的BlobByteArrayTypecdQBlobByteArrayType是用戯定义的数据类型,它实CHibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取的Lob操作句柄lobHandlerbyte[]的数据保存到Blob数据库字D中。这P我们再没有必要通过编码的方式Q先insert然后再update来完成Blobcd数据的持久化Q这个原来难伺候的老爷l于被^民化了。关于lobHandler的配|请见本文后面的内容?br />
  此外lazy="true"说明地返回整个Tfile对象Ӟq不q回fileContentq个字段的数据,只有在显式调用tfile.getFileContent()Ҏ时才真正从数据库中获取fileContent的数据。这是Hibernate3引入的新Ҏ,对于包含重量U大数据的表字段Q这U抽取方式提高了对大字段操作的灵zL,否则加蝲Tfile对象的结果集时如果Lq回fileContentQ这U批量的数据抽取可以引h据库?z泛效应"?br />
  2、DAO~写和配|?br />
  Spring面向接口~程Q所以我们将所有对Tfile的数据操作的Ҏ定义在TfileDAO接口中,q些接口Ҏ分别是:

  ·findByFildId(String fileId)

  ·save(Tfile tfile)

  ·List findAll()

  TfileDAOHibernate提供了对TfileDAO接口ZHibernate的实玎ͼ如代?3所C:

  代码 3 ZHibernate 的fileDAO实现c?br />
1. package sshfile.dao;
2.
3. import sshfile.model.*;
4. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
5. import java.util.List;
6.
7. public class TfileDAOHibernate
8. extends HibernateDaoSupport implements TfileDAO
9. {
10. public Tfile findByFildId(String fileId)
11. {
12. return (Tfile) getHibernateTemplate().get(Tfile.class, fileId);
13. }
14. public void save(Tfile tfile)
15. {
16. getHibernateTemplate().save(tfile);
17. getHibernateTemplate().flush();
18. }
19. public List findAll()
20. {
21. return getHibernateTemplate().loadAll(Tfile.class);
22. }
23. }

  TfileDAOHibernate通过扩展Spring提供的Hibernate支持cHibernateDaoSupport而徏立,HibernateDaoSupport装了HibernateTemplateQ而HibernateTemplate装了Hibernate所提供几乎所有的的数据操作方法,如execute(HibernateCallback action)Qload(Class entityClass, Serializable id)Qsave(final Object entity){等?br />
  所以我们的DAO只需要简单地调用父类的HibernateTemplate可以完成几乎所有的数据库操作了?br />
  ׃Spring通过代理Hibernate完成数据层的操作Q所以原Hibernate的配|文件hibernate.cfg.xml的信息也转移到Spring的配|文件中Q?br />
  代码 4 Spring中有关Hibernate的配|信?br />
1. QbeansQ?br />2. Q?-- 数据源的配置 //--Q?br />3. Qbean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
4. destroy-method="close"Q?br />5. Qproperty name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/Q?br />6. Qproperty name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/Q?br />7. Qproperty name="username" value="test"/Q?br />8. Qproperty name="password" value="test"/Q?br />9. Q?beanQ?br />10. Q?-- Hibernate会话工厂配置 //--Q?br />11. Qbean id="sessionFactory"
12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"Q?br />13. Qproperty name="dataSource" ref="dataSource"/Q?br />14. Qproperty name="mappingDirectoryLocations"Q?br />15. QlistQ?br />16. QvalueQclasspath:/sshfile/modelQ?valueQ?br />17. Q?listQ?br />18. Q?propertyQ?br />19. Qproperty name="hibernateProperties"Q?br />20. QpropsQ?br />21. Qprop key="hibernate.dialect"Qorg.hibernate.dialect.OracleDialectQ?propQ?br />22. Qprop key="hibernate.cglib.use_reflection_optimizer"QtrueQ?propQ?br />23. Q?propsQ?br />24. Q?propertyQ?br />25. Q?beanQ?br />26. Q?-- Hibernate 模板//--Q?br />27. Qbean id="hibernateTemplate"
28. class="org.springframework.orm.hibernate3.HibernateTemplate"Q?br />29. Qproperty name="sessionFactory" ref="sessionFactory"/Q?br />30. Q?beanQ?br />31. Q?--DAO配置 //--Q?br />32. Qbean id="tfileDAO" class="sshfile.dao.TfileDAOHibernate"Q?br />33. Qproperty name="hibernateTemplate" ref="hibernateTemplate" /Q?br />34. Q?beanQ?br />35. ?br />36. Q?beansQ?/td>

  W?~9行定义了一个数据源Q其实现cLapache的BasicDataSourceQ第11~25行定义了Hibernate的会话工厂,会话工厂cȝSpring提供的LocalSessionFactoryBeanl护Q它注入了数据源和资源映文Ӟ此外q通过一些键值对讄了Hibernate所需的属性?br />
  其中W?6行通过c\径的映射方式Q将sshfile.modelcd目录下的所有领域对象的映射文g装蝲q来Q在本文的例子里Q它装载进Tfile.hbm.xml映射文g。如果有多个映射文g需要声明,使用c\径映方式显然比直接单独指定映射文g名的方式要简ѝ?

  W?7~30行定义了Spring代理Hibernate数据操作的HibernateTemplate模板Q而第32~34行将该模板注入到tfileDAO中?br />
  需要指定的是Spring 1.2.5提供了两套Hibernate的支持包Q其中Hibernate 2相关的封装类位于org.springframework.orm.hibernate2.*包中Q而Hibernate 3.0的封装类位于org.springframework.orm.hibernate3.*包中Q需要根据您所选用Hibernate版本q行正确选择?br />
  3、Lob字段处理的配|?br />
  我们前面已经指出Oracle的Lob字段和一般类型的字段在操作上有一个明昄区别--那就是你必须首先通过Oracle的empty_blob()/empty_clob()初始化Lob字段Q然后获取该字段的引用,通过q个引用更改其倹{所以要完成对Lob字段的操作,Hibernate必须执行两步数据库访问操作,先Insert再Update?br />
  使用BlobByteArrayType字段cd后,Z么我们就可以象一般的字段cd一h作Blob字段呢?可以定的一ҎQBlobByteArrayType不可能逾越Blob天生的操作方式,原来是BlobByteArrayType数据cd本n具体数据讉K的功能,它通过LobHandler两ơ数据访问的动作隐藏hQBlob字段的操作在表现上和其他一般字D业cd无异Q所以LobHandlerx那个"苦了我一个,q福十亿?的那位幕后英雄?br />
  LobHandler必须注入到Hibernate会话工厂sessionFactory中,因ؓsessionFactory负责产生与数据库交互的Session。LobHandler的配|如代码 5所C:

  代码 5 Lob字段的处理句柄配|?br />
1. QbeansQ?br />2. ?br />3. Qbean id="nativeJdbcExtractor"
4. class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
5. lazy-init="true"/Q?br />6. Qbean id="lobHandler"
7. class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true"Q?br />8. Qproperty name="nativeJdbcExtractor"Q?br />9. Qref local="nativeJdbcExtractor"/Q?br />10. Q?propertyQ?br />11. Q?beanQ?br />12. ?br />13. Q?beansQ?/td>

  首先Q必d义一个能够从q接池中抽取出本地数据库JDBC对象Q如OracleConnectionQOracleResultSet{)的抽取器QnativeJdbcExtractorQ这h可以执行一些特定数据库的操作。对于那些仅装了Connection而未包括Statement的简单数据连接池QSimpleNativeJdbcExtractor是效率最高的抽取器实现类Q但具体到apache的BasicDataSourceq接池,它封装了所有JDBC的对象,q时需要用CommonsDbcpNativeJdbcExtractor了。Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器:

  ·WebLogicQWebLogicNativeJdbcExtractor

  ·WebSphereQWebSphereNativeJdbcExtractor

  ·JBossQJBossNativeJdbcExtractor

  在定义了JDBC抽取器后Q再定义lobHandler。Spring 1.2.5提供了两个lobHandlerQ?br />
  ·DefaultLobHandlerQ适用于大部分的数据库Q如SqlServerQMySQLQ对Oracle 10g也适用Q但不适用于Oracle 9iQ看来Oracle 9i实是个怪胎Q谁叫Oracle 公司自己都说Oracle 9i是一个过渡性的产品呢)?br />
  ·OracleLobHandlerQ适用于Oracle 9i和Oracle 10g?br />
  ׃我们的数据库是Oracle9iQ所以用OracleLobHandler?br />
  在配|完LobHandler后, q需要将其注入到sessionFactory的Bean中,下面是调用后的sessionFactory Bean的配|:

  代码 6 lobHandler注入到sessionFactory中的配置

1. QbeansQ?br />2. ?br />3. Qbean id="sessionFactory"
4. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"Q?br />5. Qproperty name="dataSource" ref="dataSource"/Q?br />6. Q?-- 为处理Blobcd字段的句柄声?//--Q?br />7. Qproperty name="lobHandler" ref="lobHandler"/Q?br />8. ?br />9. Q?beanQ?br />10. ?br />11. Q?beansQ?/td>

  如第7所C,通过sessionFactory的lobHandler属性进行注入?br />
  业务?/b>

  1、业务层接口

  "面向接口而非面向cȝE?是Spring不遗余力所推荐的编E原则,q条原则也已lؓ大部开发者所接受Q此外,JDK的动态代理只Ҏ口有效,否则必须使用CGLIB生成目标cȝ子类。我们依从于Spring的倡导Z务类定义一个接口:

  代码 7 业务层操作接?br />
1. public interface FileService
2. {
3. void save(FileActionForm fileForm);//提交的上传文g保存到数据表?br />4. List getAllFile();//得到T_FILE所C?br />5. void write(OutputStream os,String fileId);//某个文件的文g数据写出到输出流?br />6. String getFileName(String fileId);//获取文g?br />7. }

  其中save(FileActionForm fileForm)ҎQ将装在fileForm中的上传文g保存到数据库中,q里我们使用FileActionForm作ؓҎ入参QFileActionForm是Web层的表单数据对象Q它装了提交表单的数据。将FileActionForm直接作ؓ业务层的接口入参Q相当于Web层传播到业务层中去,卛_业务层绑定在特定的Web层实现技术中Q按照分层模型学院派的观点,q是一U反模块化的设计Q但?一?的业务系lƈ无需提供多种UI界面Q系lWeb层将来切换到另一U实现技术的可能性也微乎其微Q所以笔者觉得没有必要ؓ了这个业务层完全独立于调用层的过高目标而去搞一个额外的隔离层,费了原材料不说Q还系l搞得过于复杂,相比于其它原则,"?始终是最大的一条原则?br />
  getAllFile()负责获取T_FILE表所有记录,以便在网上昄出来?br />
  而getFileName(String fileId)和write(OutputStream os,String fileId)则用于下载某个特定的文g。具体的调用是将Web层将response.getOutputStream()传给write(OutputStream os,String fileId)接口Q业务层直接文件数据输出到q个响应中。具体实现请参见错误Q未扑ֈ引用源。节下蝲文g部分?br />
  2、业务层接口实现c?br />
  FileService的实现类为FileServiceImplQ其中save(FileActionForm fileForm)的实现如下所C:

  代码 8 业务接口实现cMsave()

1. ?br />2. public class FileServiceImpl
3. implements FileService
4. {
5. private TfileDAO tfileDAO;
6. public void save(FileActionForm fileForm)
7. {
8. Tfile tfile = new Tfile();
9. try
10. {
11. tfile.setFileContent(fileForm.getFileContent().getFileData());
12. }
13. catch (FileNotFoundException ex)
14. {
15. throw new RuntimeException(ex);
16. }
17. catch (IOException ex)
18. {
19. throw new RuntimeException(ex);
20. }
21. tfile.setFileName(fileForm.getFileContent().getFileName());
22. tfile.setRemark(fileForm.getRemark());
23. tfileDAO.save(tfile);
24. }
25. ?br />26. }

  在save(FileActionForm fileForm)Ҏ里,完成两个步骤Q?br />
  其一Q象在水桉倒水一PFileActionForm对象中的数据倒入到Tfile对象中;

  其二Q调用TfileDAO保存数据?br />
  需要特别注意的是代码的W?1行,FileActionForm的fileContent属性ؓorg.apache.struts.upload.FormFilecdQFormFile提供了一个方便的ҎgetFileData()Q即可获取文件的二进制数据。通过解读FormFile接口实现cDiskFile的原码,我们可能知道FormFile本nq不~存文g的数据,只有实际调用getFileData()Ӟ才从盘文g输入中获取数据。由于FormFile使用读取方式获取数据,本n没有~存文g的所有数据,所以对于上传超大体U的文gQ也是没有问题的Q但是,׃数据持久层的Tfile使用byte[]来缓存文件的数据Q所以ƈ不适合处理大体积的文Ӟ?00MQ,对于大体积的文Ӟ依然需要用java.sql.Blobcd以常规流操作的方式来处理?br />
  此外Q通过FileForm的getFileName()Ҏ可以获得上传文件的文g名,如第21行代码所C?br />
  write(OutputStream os,String fileId)Ҏ的实玎ͼ如代?9所C:

  代码 9 业务接口实现cMwrite()

1. ?br />2. public class FileServiceImpl
3. implements FileService
4. {
5.
6. public void write(OutputStream os, String fileId)
7. {
8. Tfile tfile = tfileDAO.findByFildId(fileId);
9. try
10. {
11. os.write(tfile.getFileContent());
12. os.flush();
13. }
14. catch (IOException ex)
15. {
16. throw new RuntimeException(ex);
17. }
18. }
19. ?br />20. }

  write(OutputStream os,String fileId)也简单地分ؓ两个操作步骤Q首先,ҎfileId加蝲表记录,然后fileContent写入到输出流中?br />
  3、Spring事务配置

  下面Q我们来看如何在Spring配置文g中ؓFileService配置声明性的事务

1. QbeansQ?br />2. ?
3. Qbean id="transactionManager"
4. class="org.springframework.orm.hibernate3.HibernateTransactionManager"Q?br />5. Qproperty name="sessionFactory" ref="sessionFactory"/Q?br />6. Q?beanQ?br />7. Q?-- 事务处理的AOP配置 //--Q?br />8. Qbean id="txProxyTemplate" abstract="true"
9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"Q?br />10. Qproperty name="transactionManager" ref="transactionManager"/Q?br />11. Qproperty name="transactionAttributes"Q?br />12. QpropsQ?br />13. Qprop key="get*"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />14. Qprop key="find*"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />15. Qprop key="save"QPROPAGATION_REQUIREDQ?propQ?br />16. Qprop key="write"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />17. Q?propsQ?br />18. Q?propertyQ?br />19. Q?beanQ?br />20. Qbean id="fileService" parent="txProxyTemplate"Q?br />21. Qproperty name="target"Q?br />22. Qbean class="sshfile.service.FileServiceImpl"Q?br />23. Qproperty name="tfileDAO" ref="tfileDAO"/Q?br />24. Q?beanQ?br />25. Q?propertyQ?br />26. Q?beanQ?br />27. Q?beansQ?/td>

  Spring的事务配|包括两个部分:

  其一Q定义事务管理器transactionManagerQ用HibernateTransactionManager实现事务理Q?br />
  其二Q对各个业务接口q行定义Q其实txProxyTemplate和fileService是父子节点的关系Q本来可以将txProxyTemplate定义的内容合q到fileService中一起定义,׃我们的系l仅有一个业务接口需要定义,所以将其定义的一部分抽象到父节点txProxyTemplate中意义确实不大,但是对于真实的系l,往往拥有为数众多的业务接口需要定义,这些业务接口定义内容的共同部分抽取C个父节点中,然后在子节点中通过parentq行兌Q就可以大大化业务接口的配置了?br />
  父节点txProxyTemplate注入了事务管理器Q此外还定义了业务接口事务管理的ҎQ允讔R过通配W的方式q行匚w声明Q如前两个接口方法)Q有些接口方法仅Ҏ据进行读操作Q而另一些接口方法需要涉及到数据的更攏V对于前者,可以通过readOnly标识出来Q这h利于操作性能的提高,需要注意的是由于父c节点定义的Bean仅是子节炚w|信息的抽象Qƈ不能具体实现化一个Bean对象Q所以需要特别标注ؓabstract="true"Q如W?行所C?br />
  fileService作ؓ一个目标类被注入到事务代理器中Q而fileService实现cL需要的tfileDAO实例Q通过引用3.2节中定义的tfileDAO Bean注入?br />
  Web层实?/b>

  1、Web层的构g和交互流E?br />
  Web层包括主?个功能:

  ·上传文g?br />
  ·列出所有已l上传的文g列表Q以供点M载?br />
  ·下蝲文g?br />
  Web层实现构件包括与2个JSP面Q?个ActionForm及一个ActionQ?br />
  ·file-upload.jspQ上传文件的面?br />
  ·file-list.jspQ已l上传文件的列表面?br />
  ·FileActionFormQfile-upload.jsp面表单对应的ActionForm?br />
  ·FileActionQ承org.apache.struts.actions.DispatchAction的ActionQ这栯个Action可以通过一个URL参数区分中响应不同的h?br />
  Web层的q些构g的交互流E如?6所C:


?6 Web层Struts程?/div>

  其中Q在执行文g上传的请求时QFileAction在执行文件上传后Qforward到loadAllFile出口中,loadAllFile加蝲数据库中所有已l上传的记录Q然后forward到名为fileListPage的出口中Q调用file-list.jsp面昄已经上传的记录?br />
  2、FileAction功能

  Struts 1.0的Action有一个弱:一个Action只能处理一U请求,Struts 1.1中引入了一个DispatchActionQ允讔R过URL参数指定调用Action中的某个ҎQ如http://yourwebsite/fileAction.do?method=upload卌用FileAction中的uploadҎ。通过q种方式Q我们就可以一些相关的h集中C个Action当中~写Q而没有必要ؓ某个h操作~写一个ActioncR但是参数名是要在struts-config.xml中配|的Q?br />
1. Qstruts-configQ?br />2. Qform-beansQ?br />3. Qform-bean name="fileActionForm" type="sshfile.web.FileActionForm" /Q?br />4. Q?form-beansQ?br />5. Qaction-mappingsQ?br />6. Qaction name="fileActionForm" parameter="method" path="/fileAction"
7. type="sshfile.web.FileAction"Q?br />8. Qforward name="fileListPage" path="/file-list.jsp" /Q?br />9. Qforward name="loadAllFile" path="/fileAction.do?method=listAllFile" /Q?br />10. Q?actionQ?br />11. Q?action-mappingsQ?br />12. Q?struts-configQ?/td>

  W?行的parameter="method"指定了承载方法名的参敎ͼW?行中Q我们还配置了一个调用FileAction不同Ҏ的Action出口?br />
  FileAction共有3个请求响应的ҎQ它们分别是Q?br />
  ·upload(?Q处理上传文件的h?br />
  ·listAllFile(?Q处理加载数据库表中所有记录的h?br />
  ·downloadQ…)Q处理下载文件的h?br />
  下面我们分别对这3个请求处理方法进行讲解?br />
  2.1 上传文g

  上传文g的请求处理方法非常简单,之言之,是从Spring容器中获取业务层处理cFileServiceQ调用其save(FileActionForm form)Ҏ上传文gQ如下所C:

1. public class FileAction
2. extends DispatchAction
3. {
4. //上传文件保存到数据库中
5. public ActionForward upload(ActionMapping mapping, ActionForm form,
6. HttpServletRequest request,
7. HttpServletResponse response)
8. {
9. FileActionForm fileForm = (FileActionForm) form;
10. FileService fileService = getFileService();
11. fileService.save(fileForm);
12. return mapping.findForward("loadAllFile");
13. }
14. //从Spring容器中获取FileService对象
15. private FileService getFileService()
16. {
17. ApplicationContext appContext = WebApplicationContextUtils.
18. getWebApplicationContext(this.getServlet().getServletContext());
19. return (FileService) appContext.getBean("fileService");
20. }
21. ?br />22. }

  ׃FileAction其它两个h处理Ҏ也需要从Spring容器中获取FileService实例Q所以我们特别提供了一个getFileService()ҎQ第15~21行)。重构的一条原则就是:"发现代码中有重复的表辑ּQ将其提取ؓ一个变量;发现cM有重复的代码D,其提取Z个方法;发现不同cM有相同的ҎQ将其提取ؓ一个类"。在真实的系l中Q往往拥有多个Action和多个Servicec,q时一个比较好的设|思\是,提供一个获取所有Service实现对象的工LQ这样就可以Spring 的Service配置信息屏蔽在一个类中,否则Service的配|名字散落在E序各处Q维护性是很差的?br />
  2.2 列出所有已l上传的文g

  listAllFileҎ调用Servie层方法加载T_FILE表中所有记录,q将其保存在Request域中Q然后forward到列表页面中Q?br />
1. public class FileAction
2. extends DispatchAction
3. {
4. ?br />5. public ActionForward listAllFile(ActionMapping mapping, ActionForm form,
6. HttpServletRequest request,
7. HttpServletResponse response)
8. throws ModuleException
9. {
10. FileService fileService = getFileService();
11. List fileList = fileService.getAllFile();
12. request.setAttribute("fileList",fileList);
13. return mapping.findForward("fileListPage");
14. }
15. }

  file-list.jsp面使用Struts标签展示Z存在Request域中的记录:

1. Q?@page contentType="text/html; charset=GBK"%Q?br />2. Q?@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%Q?br />3. Q?@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%Q?br />4. QhtmlQ?br />5. QheadQ?br />6. QtitleQfile-downloadQ?titleQ?br />7. Q?headQ?br />8. Qbody bgcolor="#ffffff"Q?br />9. QolQ?br />10. Qlogic:iterate id="item" name="fileList" scope="request"Q?br />11. QliQ?br />12. Qa href='fileAction.do?method=download&fileId=
13. Qbean:write name="item"property="fileId"/Q?Q?br />14. Qbean:write name="item" property="fileName"/Q?br />15. Q?aQ?br />16. Q?liQ?br />17. Q?logic:iterateQ?br />18. Q?olQ?br />19. Q?bodyQ?br />20. Q?htmlQ?/td>

  展现面的每条记录挂接着一个链接地址QŞ如:fileAction.do?method=download&fileId=xxxQmethod参数指定了这个请求由FileAction的downloadҎ来响应,fileId指定了记录的主键?br />
  ׃在FileActionForm中,我们定义了fileId的属性,所以在download响应Ҏ中,我们可以从FileActionForm中取得fileId的倹{这里涉及到一个处理多个请求Action所对应的ActionForm的设计问题,׃原来的Action只能对应一个请求,那么原来的ActionForm非常单,它仅需要将q个h的参数项作ؓ其属性就可以了,但现在一个Action对应多个hQ每个请求所对应的参数项是不一LQ此时的ActionForm的属性就必须是多h参数的q了。所以,除了文g上传h所对应的fileContent和remark属性外q包括文件下载的fileId属性:


?7 FileActionForm

  当然q样会造成属性的冗余Q比如在文g上传的请求中Q只会用到fileContent和remark属性,而在文g下蝲的请求时Q只会用到fileId属性。但q种冗余是会带来好处?-它得一个Action可以处理多个h?br />
  2.3 下蝲文g

  在列表页面中点击一个文件下载,其请求由FileAction的downloadҎ来响应,downloadҎ调用业务层的FileServiceҎQ获取文件数据ƈ写出到response的响应流中。通过合理讄HTTP响应头参敎ͼ响应流在客L表现Z个下载文件对话框Q其代码如下所C:

  代码 10 业务接口实现cMdownload

1. public class FileAction
2. extends DispatchAction
3. {
4. ?br />5. public ActionForward download(ActionMapping mapping, ActionForm form,
6. HttpServletRequest request,
7. HttpServletResponse response)
8. throws ModuleException
9. {
10. FileActionForm fileForm = (FileActionForm) form;
11. FileService fileService = getFileService();
12. String fileName = fileService.getFileName(fileForm.getFileId());
13. try
14. {
15. response.setContentType("application/x-msdownload");
16. response.setHeader("Content-Disposition",
17. "attachment;" + " filename="+
18. new String(fileName.getBytes(), "ISO-8859-1"));
19. fileService.write(response.getOutputStream(), fileForm.getFileId());
20. }
21. catch (Exception e)
22. {
23. throw new ModuleException(e.getMessage());
24. }
25. return null;
26. }
27. }

  W?5~18行,讄HTTP响应_响应类型设|ؓapplication/x-msdownload MIMEcdQ则响应在IE中将弹出一个文件下载的对话框,如图 4所C。IE所支持的MIMEcd多达26U,您可以通过q个|址查看其他的MIMEcdQ?br />
http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp?br />
  如果下蝲文g的文件名含有中文字符Q如果不对其q行编码,如第18行所C,客户文g下蝲对话框中出现的文件名会发生q?br />W?9行代码获得response的输出流Q作为FileServie write(OutputStream os,String fileId)的入参,q样文g的内容将写到response的输出流中?br />
  3、web.xml文g的配|?br />
  Spring容器在何时启动呢Q我可以在Web容器初始化来执行启动Spring容器的操作,Spring提供了两U方式启动的ҎQ?br />
  ·通过org.springframework.web.context .ContextLoaderListener容器监听器,在Web容器初始化时触发初始化Spring容器Q在web.xml中通过QlistenerQ</listenerQ对其进行配|?br />
  ·通过Servlet org.springframework.web.context.ContextLoaderServletQ将光|ؓ自动启动的ServletQ在Web容器初始化时Q通过q个Servlet启动Spring容器?br />
  在初始化Spring容器之前Q必d初始化log4J的引擎,Spring也提供了容器监听器和自动启动Servlet两种方式对log4J引擎q行初始化:

  ·org.springframework.web.util .Log4jConfigListener

  ·org.springframework.web.util.Log4jConfigServlet

  下面我们来说明如何配|web.xml启动Spring容器Q?br />
  代码 11 web.xml中对应Spring的配|内?br />
1. Qweb-appQ?br />2. Qcontext-paramQ?br />3. Qparam-nameQcontextConfigLocationQ?param-nameQ?br />4. Qparam-valueQ?WEB-INF/applicationContext.xmlQ?param-valueQ?br />5. Q?context-paramQ?br />6. Qcontext-paramQ?br />7. Qparam-nameQlog4jConfigLocationQ?param-nameQ?br />8. Qparam-valueQ?WEB-INF/log4j.propertiesQ?param-valueQ?br />9. Q?context-paramQ?br />10. QservletQ?br />11. Qservlet-nameQlog4jInitServletQ?servlet-nameQ?br />12. Qservlet-classQorg.springframework.web.util.Log4jConfigServletQ?servlet-classQ?br />13. Qload-on-startupQ?Q?load-on-startupQ?br />14. Q?servletQ?br />15. QservletQ?br />16. Qservlet-nameQspringInitServletQ?servlet-nameQ?br />17. Qservlet-classQorg.springframework.web.context.ContextLoaderServletQ?servlet-classQ?br />18. Qload-on-startupQ?Q?load-on-startupQ?br />19. Q?servletQ?br />20. ?br />21. Q?web-appQ?/td>

  启动Spring容器Ӟ需要得C个信息:Spring配置文g的地址和Log4J属性文Ӟq两上信息分别通过contextConfigLocationWeb和log4jConfigLocation容器参数指定Q如果有多个Spring配置文gQ则用逗号隔开Q如Q?br />
/WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2

  ׃在启动ContextLoaderServlet之前Q必M先初始化Log4J的引擎,所以Log4jConfigServlet必须在ContextLoaderServlet之前启动Q这通过Qload-on-startupQ来指定它们启动的先后顺序?br />
  q是开发Web应用E序一个比较老套又常见问题,׃不同Web应用服务器的默认~码是不一LQؓ了方便Web应用在不同的Web应用服务器上ULQ最好的做法是WebE序自n来处理编码{换的工作。经典的作法是在web.xml中配|一个编码{换过滤器QSpring提供了一个编码过滤器cCharacterEncodingFilterQ下面,我们为应用配|上q个qo器:

1. Qweb-appQ?br />2. ?br />3. QfilterQ?br />4. Qfilter-nameQencodingFilterQ?filter-nameQ?br />5. Qfilter-classQorg.springframework.web.filter.CharacterEncodingFilterQ?filter-classQ?br />6. Qinit-paramQ?br />7. Qparam-nameQencodingQ?param-nameQ?br />8. Qparam-valueQGBKQ?param-valueQ?br />9. Q?init-paramQ?br />10. Q?filterQ?br />11. Qfilter-mappingQ?br />12. Qfilter-nameQencodingFilterQ?filter-nameQ?br />13. Qurl-patternQ?*Q?url-patternQ?br />14. Q?filter-mappingQ?br />15. ?br />16. Q?web-appQ?/td>

  Spring的过滤器cLorg.springframework.web.filter.CharacterEncodingFilterQ通过encoding参数指定~码转换cd为GBKQ<filter-mappingQ的配置使该qo器截h有的L?br />
  Struts的框架也需要在web.xml中配|,惛_读者朋友对Struts的配|都很熟悉,故在此不再提及,请参见本文所提供的源码?br />
  ȝ

  本文通过一个文件上传下载的Web应用Q讲解了如何构徏ZSSH的Web应用Q通过Struts和FormFileQSpring的LobHandler以及Spring为HibernateBlob处理所提供的用LBlobByteArrayType Q实C传和下蝲文g的功能仅需要廖廖数行的代码卛_完成。读者只需对程序作E许的调_卛_处理Clob字段Q?br />
  ·领域对象对应Clob字段的属性声明ؓStringcdQ?br />
  ·映射文g对应Clob字段的属性声明ؓorg.springframework.orm.hibernate3.support.ClobStringTypecd?br />
  本文通过SSHҎ件上传下载简捷完的实现得以中Hv了解SSH强强联合构徏Web应用的强大优ѝ在行文中,q穿插了一些分层的设计l验Q配|技巧和Spring所提供的方便类Q相信这些知识对您的开发都有所裨益?img src ="http://www.tkk7.com/rendong/aggbug/60977.html" width = "1" height = "1" />

rendong 2006-07-31 11:23 发表评论
]]>
վ֩ģ壺 6080yyþԹ| ˳Ƶ߹ۿվ | ձһƵۿ| þþþAVר| ŪƵ| ߹ۿHַ| ij˾þþþӰԺѹۿ | 99reѾƷƵۿ| ߹ۿxxxx| ؼëƬѹۿƵ| ۺϾƷ| ŷƵ߹ۿ| ޹AV| պߵһҳ| ҹˬˬˬWWWƵʮ˽| պavһ| һëƬaaaaaaѿ| ĻѲƵ| AVһ| ˳ͼƬվ| ޹һ߹ۿ| ĻۺϾþ2| vavavaĻ| ҹþþþþ| ޹þþþþþ| һƵ| ߿Ƭa| ѿbbb| Ƶ| Ů˱ͰúˬƵ| ߹ۿѸƵ| һƵ| Ļ벻Ƶ | ˬ AVˬ| ӰԺ߲| ۺһ| ޹Ʒ˾þþ| 91ҹƷһ| ޹Ƶ| ޾Ʒ߹ۿ| ޾ƷþþþAƬԾ|