最近偶參與一個J2EE項目,應用架框是struts+spring! 持久層用hibernate,由于業務需要,業務數據來源來二個不同的數據庫數據庫是Orcale,版本是9.0.1.0.0。由于采用容器管理事務(CMT),對于Spring,一般普通業務應用我用聲明式事務,因為這樣讓代碼清潔一點,只有對于特殊的業務我才用編程式事務,如大批量更新時調用存儲過程。對于WebLogic Server,JTA TransactionManager的正式JNDI位置是javax.transaction.TransactionManager。在Spring 的JtaTransactionManager中,該值可被指定為“transactionManagerName”。這啟用了使用WebLogic JTA子系統的Spring驅動的事務掛起激活了對PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUPPORTED的支持。對于聲明式事務我配置在spring的service層,對于編程式事務則在持久層。
下面說一下我的系統分層:acton==>service==>serviceImpl===>DAO===>DAOImpl,由業務層的實現類調用持久層的DAO接口,為了避免DAO的過度設計而使重用性降低,我這里每一個DAO接口對應操作數據庫表,由spring的IOC容器注入,這樣在serviceImpl層中可以最大程序的重用DAO。因為由于業務需要一個serviceImpl需要從兩個數據庫中交換數據。操作DAO可以保證處于同一個事務中......
事務的屬性和基本概念
Required:
如果在一個事務中調用,就把該方法加到此事務中來,如果還沒有啟動事務,就啟動一個新事務。
RequiredNew:
不管當前有沒有事務,都會啟動一個新事務,如果當前有事務,會被掛起直到方法結束。
NotSupported:
不能在事務中執行此方法。如果有事務,將會被掛起直到方法結束。
Supports:
如果當前有事務,此方法會加到當前事務,如果沒有,容器也不會啟動新事務。
Mandatory:
必須在事務中調用此方法,否則拋出異常:TransactionRequiredException。
Never:
必須不在事務中調用此方法,否則拋出RemoteException(遠程調用)或EJBException(本地調用)
以下FAQ來自http://dev2dev.bea.com.cn
Q:XA 的Driver 和普通的Driver 有什么區別呢?
A: XA 的Driver 支持分布式的事務處理,這是與non xa driver 的最大區別;JDBC2.0 規范提供了進行分布式事務的能力。分布式事務是個單獨的事務,可以應用在位于分離服務器上的多個異構數據庫。為了支持分布式事務, JDBC2.0 提供了兩個新的接口:javax.sql.XADataSource 和javax.sql.XAConnection。從性能的考慮來說,使用XA 的DRIVER
會比普通的DRIVER 慢。
Q: XA 的連接池,選擇了支持本地事務后,是否還支持對全局的操作?
A: 8.1 既支持TX,也支持Non-Tx 的,Weblogic 對所有的已知數據庫進行了包裝(Wrapper),使接口一致,然而對不同的數據庫,根據選擇的驅動程序不同,都作了相應的優化和處理。建立數據源時,如果選擇Non-Tx 類型,那么它參與到JTA 事務中也不會出錯,因為Weblogic 會啟動本地事務,但是前提是必須有一個資源(XAResource)參與到事務中(多個資源的話必須打開模擬兩
階段提交協議,不然會出錯),但是選擇Tx 類型的就必須有一個全局事務,除非選擇支持本地事務(SupportsLocalTransaction=true)。另外如果使用了本地事務,就必須設置autocommit 為true,或者手工commit/rollback。
Q: 資料上講distributed transaction 只能用JTA 的XAResource 來控制事務,如JMS 要參加分布式事務的話就必須用XA 的。但是,我記得在我們的應用中如果在一個容器管理的事務中修改兩個不同的數據庫(這兩個庫在一臺機器的同一個實例中),那么必須用XA 的driver,難道這也是一種distribued transaction 嗎?(它們是同一種資源,都是JDBC,只是跨庫而已,為什么屬于分布式事務呢?)
A: 分布式事務分事務管理器,資源管理器,應用程序,以及底層事務通訊管理.在xa 中一個db就是一個資源.一個jms 也可以看作是一個資源,事務管理器就是協調這些資源進行統一commit 或者rollback 的,所以來說跨庫就屬于分布式事務了。
具體操作步驟:
1、Configure a new JDBC Connection Pool:先在weblogic console中配置連接池,這里用
Oracle's Deriver(Thin XA) Versions:8.1.7.9.0.1.9.2.0, 并把Supports Local Transaction勾上。
2、Configure a new JDBC Data Source:配置一個數據源,并綁定上面創建的連接池。
3、在spring的ApplicationContext.xml中配置:
1
Jndi:
2
<bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
3
<property name="jndiName">
4
<value>ds1</value>
5
</property>
6
</bean>
7
8
<bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
9
<property name="jndiName">
10
<value>ds2</value>
11
</property>
12
</bean>
13
14
Jta:
15
<bean id="myTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
16
17
SessionFactory:
18
<bean id="mySessionFactory1" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
19
<property name="mappingResources">
20
<list>
21
<value>myOne.hbm.xml</value>
22
<value>myTwo.hbm.xml</value>
23
</list>
24
</property>
25
<property name="hibernateProperties">
26
<props>
27
<prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop>
28
<prop key="hibernate.show_sql">true</prop>
29
<prop key="hibernate.jdbc.fetch_size">50</prop>
30
<prop key="hibernate.jdbc.batch_size">0</prop>
31
</props>
32
</property>
33
<property name="dataSource">
34
<ref bean="myDataSource1"/>
35
</property>
36
</bean>
37
38
<bean id="mySessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
39
<property name="mappingResources">
40
<list>
41
<value>youOne.hbm.xml</value>
42
<value>youTwo.hbm.xml</value>
43
</list>
44
</property>
45
<property name="hibernateProperties">
46
<props>
47
<prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop>
48
<prop key="hibernate.show_sql">true</prop>
49
<prop key="hibernate.jdbc.fetch_size">50</prop>
50
<prop key="hibernate.jdbc.batch_size">0</prop>
51
</props>
52
</property>
53
<property name="dataSource">
54
<ref bean="myDataSource2"/>
55
</property>
56
</bean>
57
58
TranscationManager
59
<bean id="TransactionProxyFactoryBean" abstract="true" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
60
<property name="transactionManager" ><ref bean="myTransactionManager" /></property>
61
<property name="transactionAttributes" >
62
<props>
63
<prop key="find*" >PROPAGATION_REQUIRED,readonly</prop>
64
<prop key="save*" >PROPAGATION_REQUIRED</prop>
65
<prop key="update*" >PROPAGATION_REQUIRED</prop>
66
<prop key="delete*" >PROPAGATION_REQUIRED</prop>
67
<prop key="do*" >PROPAGATION_REQUIRED</prop>
68
</props>
69
</property>
70
</bean>
71
72
DAO配置
73
<bean id="serviceImpl" parent="TransactionProxyFactoryBean">
74
<property name="target">
75
<bean class="com.hi.services.spring.business.SomeServiceImpl">
76
<property name="dao1"><ref local="dao1"/></property>
77
<property name="dao2"><ref local="dao2"/></property>
78
<property name="dao3"><ref local="dao3"/></property>
79
</bean>
80
</property>
81
</bean>
82
83
4 修改weblogic服務器你發布的domains文件下的config.xml,加上RollbackLocalTxUponConnClose="true",如果這句話不加上
84
insert*、delete*、upate*無法提交。
85
<JDBCConnectionPool
86
DriverName="oracle.jdbc.xa.client.OracleXADataSource"
87
Name="baseXaPool" Password="{3DES}RBDwPC7KmTq1MGymoUMieg=="
88
Properties="user=admin" RollbackLocalTxUponConnClose="true"
89
SupportsLocalTransaction="true" Targets="myserver"
90
TestConnectionsOnCreate="false" TestConnectionsOnRelease="false"
91
TestConnectionsOnReserve="false"
92
TestTableName="SQL SELECT 1 FROM DUAL" URL="jdbc:oracle:thin:@192.168.0.7:1521:flyjie"/>
93
<JDBCConnectionPool
94
DriverName="oracle.jdbc.xa.client.OracleXADataSource"
95
Name="applicationXaPool" Password="{3DES}RBDwPC7KmTq1MGymoUMieg=="
96
Properties="user=flyjie" RollbackLocalTxUponConnClose="true"
97
SupportsLocalTransaction="true" Targets="myserver"
98
TestConnectionsOnCreate="false" TestConnectionsOnRelease="false"
99
TestConnectionsOnReserve="false"
100
TestTableName="SQL SELECT 1 FROM DUAL" URL="jdbc:oracle:thin:@192.168.0.55:1521:application"/>
101
102
一個例子:
103
public class SomeServiceImpl implements ISomeService
{
104
105
private IDao1 dao1; //操作mySessionFactory1的表
106
private IDao2 dao2; //操作mySessionFactory2的表
107
private IDao3 dao3; //操作mySessionFactory1的表
108
//
.get
109
110
///
set
111
public Object doIn(Object[] object)
{
112
String sql = (String)object[1];
113
List resultList = (ArrayList)getIDao1().findPeronList(sql);
114
//..某些業務操作
115
for(
.)
116
getIDao2().save(resultList.get(i));
117
//

118
update(object);
119
}
120
121
public void update(Object object)
{
122
getIDao3().update(//
);
123
}
124
}
注意的問題:由于配置不當引起的serive層中的事務嵌套,這一個人很惱人的問題。我們在配置聲明式事務時一般是以service層中的方法名來作來啟動事務的標志。如save*,find*,你的serviceImpl中有save方法或findList方法,
spring會在自動把在該方法內操作的資源納入到同一個事務中,以保證數據ACID(Atomicity、Consistency、Isolation、Durability)。
關于Spring的事務請參考Spring Framework 開發參考手冊
http://www.jactiongroup.net/reference/html/index.html
posted on 2005-11-24 16:47
java驛館 閱讀(2350)
評論(1) 編輯 收藏 所屬分類:
J2EE隨談