原創(chuàng)|其它|編輯:郝浩|2009-08-28 11:43:10.000|閱讀 2407 次
概述:TopLink本身并沒(méi)有提供SessionFactory抽象層邏輯,多線程的數(shù)據(jù)訪問(wèn)是建立在中央 ServerSession 上的。對(duì)于單線程訪問(wèn), 這個(gè)中央 ServerSession 會(huì)為它一個(gè) ClientSession 的實(shí)例供其使用。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
SessionFactory 抽象層
TopLink本身并沒(méi)有提供SessionFactory抽象層邏輯,多線程的數(shù)據(jù)訪問(wèn)是建立在中央 ServerSession 上的。對(duì)于單線程訪問(wèn), 這個(gè)中央 ServerSession 會(huì)為它一個(gè) ClientSession 的實(shí)例供其使用。為了提供靈活便捷的創(chuàng)建選項(xiàng), Spring為TopLink定義了一個(gè) SessionFactory 接口,從而使你可以任意地在不同的 Session 創(chuàng)建策略之間進(jìn)行切換。
作為一個(gè)一站式的商店,Spring提供了一個(gè) LocalSessionFactoryBean 類,允許你以bean風(fēng)格的配置方式來(lái)定義一個(gè)TopLink SessionFactory。 需要進(jìn)行配置的地方主要是TopLink session配置文件,通常來(lái)說(shuō)還需配置一個(gè)受到Spring管理的JDBC DataSource。
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource " destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="mySessionFactory" class="org.springframework.orm.toplink. LocalSessionFactoryBean">
<property name="configLocation" value="toplink-sessions.xml"/>
<property name="dataSource" ref="dataSource"/>
bean>
beans>
<toplink-configuration>
<session>
<name>Sessionname>
<project-xml>toplink-mappings.xmlproject-xml>
<session-type>
<server-session/>
session-type>
<enable-logging>trueenable-logging>
<logging-options/>
session>
toplink-configuration>
通常情況下,LocalSessionFactoryBean 在底層將持有一個(gè)多線程的TopLink ServerSession 并創(chuàng)建合適的客戶端 Session: 它或者是一個(gè)普通的 Session(典型情況) —— 一個(gè)受管理的 ClientSession;或者是一個(gè)具備事務(wù)功能的 Session (后者主要在Spring內(nèi)部對(duì)TopLink的支持中被使用)。還有一種情況,LocalSessionFactoryBean 可能會(huì)持有一個(gè)單線程的TopLink的 DatabaseSession,這是非常特殊的情況了。
TopLinkTemplate & TopLinkDaoSupport
每個(gè)基于TopLink的DAO將通過(guò)IoC被注入一個(gè) SessionFactory,你可以通過(guò)Setter方式注入,也可以用構(gòu)造函數(shù)方式注入。這樣的DAO可以直接操作原生的TopLink API,通過(guò) SessionFactory 來(lái)獲取一個(gè) Session, 但是通常情況下,你更愿意使用Spring的 TopLinkTemplate:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
bean>
beans>
public class TopLinkProductDao implements ProductDao {
private TopLinkTemplate tlTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.tlTemplate = new TopLinkTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return (Collection) this.tlTemplate.execute(new TopLinkCallback() {
public Object doInTopLink(Session session) throws TopLinkException {
ReadAllQuery findOwnersQuery = new ReadAllQuery(Product.class);
findOwnersQuery.addArgument("Category");
ExpressionBuilder builder = this.findOwnersQuery.getExpressionBuilder();
findOwnersQuery.setSelectionCriteria(
builder.get("category").like(builder.getParameter("Category")));
Vector args = new Vector();
args.add(category);
List result = session.executeQuery(findOwnersQuery, args);
// do some further stuff with the result list
return result;
}
}
}
}
一個(gè)回調(diào)的實(shí)現(xiàn)能夠有效地在任何TopLink數(shù)據(jù)訪問(wèn)中使用。TopLinkTemplate 會(huì)確保當(dāng)前的 Session 對(duì)象的正確打開(kāi)和關(guān)閉,并自動(dòng)參與到事務(wù)管理中去。 Template實(shí)例不僅是線程安全的,同時(shí)它也是可重用的。因而他們可以作為外部對(duì)象的實(shí)例變量而被持有。對(duì)于那些簡(jiǎn)單的諸如 executeQuery、readAll、readById 和 merge 操作的調(diào)用,TopLinkTemplate提供可選擇的快捷函數(shù)來(lái)替換這種回調(diào)的實(shí)現(xiàn)。 不僅如此,Spring還提供了一個(gè)簡(jiǎn)便的 TopLinkDaoSupport 基類,這個(gè)類提供了 setSessionFactory(..) 方法來(lái)接受一個(gè) SessionFactory 對(duì)象,同時(shí)提供了 getSessionFactory() 和 getTopLinkTemplate() 方法給子類使用。綜合了這些,對(duì)于那些典型的業(yè)務(wù)需求,就有了一個(gè)非常簡(jiǎn)單的DAO實(shí)現(xiàn)。
public class ProductDaoImpl extends TopLinkDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
ReadAllQuery findOwnersQuery = new ReadAllQuery(Product.class);
findOwnersQuery.addArgument("Category");
ExpressionBuilder builder = this.findOwnersQuery.getExpressionBuilder();
findOwnersQuery.setSelectionCriteria(
builder.get("category").like(builder.getParameter("Category")));
return getTopLinkTemplate().executeQuery(findOwnersQuery, new Object[] {category});
}
}
邊注:TopLink查詢對(duì)象是線程安全的,并且能夠在DAO層被緩存。在一開(kāi)始被創(chuàng)建時(shí)以實(shí)例變量的方式被保持。
作為不使用Spring的 TopLinkTemplate 來(lái)實(shí)現(xiàn)DAO的替代解決方案, 你依然可以通過(guò)原生TopLink API對(duì)那些基于Spring的DAO進(jìn)行編程,此時(shí)你必須明確地打開(kāi)和關(guān) 閉一個(gè) Session。正如在相應(yīng)的Hibernate章節(jié)描述的一樣,這種做法的主要優(yōu)點(diǎn)在于你的數(shù)據(jù)訪問(wèn)代碼可以在整個(gè)過(guò)程中拋出checked exceptions。 TopLinkDaoSupport 為這種情況提供了多種函數(shù)支持,包括獲取和釋放 一個(gè)具備事務(wù)的 Session 并做相關(guān)的異常轉(zhuǎn)化。
基于原生的TopLink API的DAO實(shí)現(xiàn)
我們可以直接操作TopLink API來(lái)實(shí)現(xiàn)DAO,直接使用一個(gè)注入的 Session 而無(wú)需對(duì)Spring產(chǎn)生的任何依賴。它通常基于一個(gè)由 LocalSessionFactoryBean 定義的 SessionFactory,并通過(guò)Spring的 TransactionAwareSessionAdapter 暴露成為一個(gè) Session 類型的引用。
TopLink的 Session 接口中定義的 getActiveSession() 方法將返回當(dāng)前具備事務(wù)管理功能的 Session 對(duì)象。如果當(dāng)前沒(méi)有處于活躍狀態(tài)的事務(wù), 這個(gè)函數(shù)將返回一個(gè)共享的TopLink ServerSession,也就是說(shuō),這種情況應(yīng)該只是一個(gè)直接使用的只讀訪問(wèn)。另外還有一個(gè) getActiveUnitOfWork() 方法, 返回TopLink的與當(dāng)前事務(wù)綁定的 UnitOfWork (如果沒(méi)有當(dāng)前事務(wù)則返回 null)。
一個(gè)相應(yīng)的DAO實(shí)現(xiàn)類看上去就像下面那樣:
public class ProductDaoImpl implements ProductDao {
private Session session;
public void setSession(Session session) {
this.session = session;
}
public Collection loadProductsByCategory(String category) {
ReadAllQuery findOwnersQuery = new ReadAllQuery(Product.class);
findOwnersQuery.addArgument("Category");
ExpressionBuilder builder = this.findOwnersQuery.getExpressionBuilder();
findOwnersQuery.setSelectionCriteria(
builder.get("category").like(builder.getParameter("Category")));
Vector args = new Vector();
args.add(category);
return session.getActiveSession().executeQuery(findOwnersQuery, args);
}
}
上面我們所列出的DAO完全遵循IoC:它如同使用Spring的 TopLinkTemplate 進(jìn)行編碼那樣,非常適合在application context中進(jìn)行配置。Spring的 TransactionAwareSessionAdapter 將暴露一個(gè) Session 類型的bean的引用,并傳入到DAO中去:
<beans>
<bean id="mySessionAdapter"
class="org.springframework.orm.toplink.support. TransactionAwareSessionAdapter">
<property name="sessionFactory" ref="mySessionFactory"/>
bean>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="session" ref="mySessionAdapter"/>
bean>
beans>
這種DAO風(fēng)格的主要好處在于它僅僅依賴于TopLink自身的API,而無(wú)需引入任何的Spring 的類。從無(wú)入侵性的角度來(lái)看,這一點(diǎn)非常吸引人。同時(shí),對(duì)于TopLink的開(kāi)發(fā)人員來(lái)說(shuō)也更自然。
然而,這樣的DAO訪問(wèn)方式會(huì)拋出 TopLinkException (這是一個(gè)無(wú)需聲明或捕獲的unchecked exception),這意味著,DAO的調(diào)用者只能以普通的錯(cuò)誤來(lái)處理這些異常,除非完全依賴TopLink自身的異常體系。因而,除非你將DAO的調(diào)用者綁定到具體的實(shí)現(xiàn)策略上去,否則你將無(wú)法捕獲特定的異常原因(諸如樂(lè)觀鎖異常)。這種折中平衡或許可以被接受,如果你的應(yīng)用完全基于TopLink或者無(wú)需進(jìn)行特殊的異常處理。
這樣的DAO風(fēng)格有一個(gè)不利因素在于TopLink的標(biāo)準(zhǔn)的 getActiveSession() 函數(shù)僅僅在JTA事務(wù)中有效。而對(duì)于其他的事務(wù)管理策略尤其時(shí)本地的TopLink事務(wù),它將 無(wú)法 工作。
幸運(yùn)的是,Spring的 TransactionAwareSessionAdapter 為TopLink ServerSession 暴露了一個(gè)相應(yīng)的代理類。 這個(gè)代理類能夠在任何的事務(wù)策略之上支持TopLink的 Session.getActiveSession() 和 Session.getActiveUnitOfWork() 函數(shù),返回當(dāng)前收到Spring管理 (即便由 TopLinkTransactionManager 管理)的具備事務(wù)管理功能的 Session 實(shí)例。當(dāng)然,這個(gè)函數(shù)的標(biāo)準(zhǔn)行為依然有效:返回與當(dāng)前的JTA事務(wù)綁定的 Session 對(duì)象。 (無(wú)論這個(gè)JTA事務(wù)是由Spring的 JtaTransactionManager、 EJB CMT或者普通的JTA所驅(qū)動(dòng)的事務(wù))。
總體來(lái)說(shuō),DAO可以基于TopLink的原生API實(shí)現(xiàn),同時(shí),它依舊需要能夠參與到Spring的事務(wù)管理中。這對(duì)于那些已經(jīng)對(duì)TopLink非常熟悉的人來(lái)說(shuō)很有吸引力,因?yàn)檫@種方式更加自然。不過(guò),這種DAO將拋出 TopLinkException,因而,如果有必要的話需要明確地去做由 TopLinkException 到Spring的 DataAccessException 的轉(zhuǎn)化。
事務(wù)管理
將事務(wù)管理納入到Service操作的執(zhí)行中,你可以使用Spring通用的聲明式的事務(wù)管理功能,參加下面的例子:
xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="//www.springframework.org/schema/beans"
xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
xmlns:aop="//www.springframework.org/schema/aop"
xmlns:tx="//www.springframework.org/schema/tx"
xsi:schemaLocation="
//www.springframework.org/schema/beans //www.springframework.org/schema/beans/spring-beans-2.5.xsd
//www.springframework.org/schema/tx //www.springframework.org/schema/tx/spring-tx-2.5.xsd
//www.springframework.org/schema/aop //www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="myTxManager" class="org.springframework.orm.toplink. TopLinkTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="productDao" ref="myProductDao"/>
bean>
<aop:config>
<aop:pointcut id="productServiceMethods" expression="execution (* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
aop:config>
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
tx:attributes>
tx:advice>
beans>
注意,TopLink要求你必須在一個(gè)活躍的 工作單元(UnitOfWork) 中修改一個(gè)持久化對(duì)象(你通常不能修改由普通的TopLink的 Session 查詢返回的對(duì)象,因?yàn)檫@些對(duì)象通常是一些從二級(jí)緩存中讀出的只讀對(duì)象)。與Hibernate相比,在TopLink中并沒(méi)有一種類似脫離事務(wù)刷出(non-transactional flush)的概念。基于這種原因,TopLink需要被建立在特定的環(huán)境中,尤其是它需要為JTA同步做明確的創(chuàng)建,由此來(lái) 自行檢測(cè)一個(gè)JTA事務(wù)以及暴露一個(gè)相應(yīng)的活躍的 Session 和 UnitOfWork。這一點(diǎn)對(duì)于本地事務(wù)不是必要的,由于它已經(jīng)被 Spring的 TopLinkTransactionManager 處理,但是對(duì)于 需要參與到JTA事務(wù)中的情況,是必須的(無(wú)論是由Spring的 JtaTransactionManager、EJB CMT或者普通的JTA所驅(qū)動(dòng)的事務(wù))。
在你的基于TopLink的DAO代碼中,你可以使用 Session.getActiveUnitOfWork() 方法來(lái)訪問(wèn)當(dāng)前的 UnitOfWork 并通過(guò)它來(lái)執(zhí)行寫(xiě)操作。這將只在一個(gè)活躍的事務(wù)中有效(在一個(gè)收到Spring管理的事務(wù)或者JTA事務(wù)中)。對(duì)于特殊的需求,你同樣可以獲取單獨(dú)的 UnitOfWork 實(shí)例,它將不參與到當(dāng)前的事務(wù)中去,不過(guò)這種情況非常少。
TopLinkTransactionManager 能夠?qū)⒁粋€(gè)TopLink事務(wù)暴露給 訪問(wèn)相同的JDBC DataSource 的JDBC訪問(wèn)代碼。 前提條件是,TopLink在底層是以JDBC方式工作的并且能夠暴露底層的JDBC Connection。這種情況下,用于暴露事務(wù)的 DataSource 必須被明確指定, 它是無(wú)法被自動(dòng)檢測(cè)到的。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:IT專家網(wǎng)