javascript
在Spring中使用JTA事务管理
在Spring中使用JTA事務管理
Spring 通過AOP技術可以讓我們在脫離EJB的情況下享受聲明式事務的豐盛大餐,脫離Java EE應用服務器使用聲明式事務的道路已經(jīng)暢通無阻。但是很大部分人都還認為脫離Java EE應用服務器就無法使用JTA事務,這是一個誤解。其實,通過配合使用ObjectWeb的JOTM開源項目,不需要Java EE應用服務器,Spring也可以提供JTA事務。
正因為AOP讓Spring擁有了脫離EJB容器的聲明式事務能力,而JOTM讓我們在脫離Java EE應用服務器下?lián)碛蠮TA事務能力。所以,人們將AOP和JOTM稱為Java軟件開發(fā)的兩個圣杯。
本文將講解Spring在不同環(huán)境下提供JTA事務的配置過程,這包括:Spring中直接集成JOTM提供JTA事務管理、將JOTM集成到Tomcat中,Spring通過引用Tomcat JNDI數(shù)據(jù)源提供JTA事務管理、引用其他功能完善JavaEE應用服務器所提供的JTA事務管理。
通過集成JOTM,直接在Spring中使用JTA事務
JOTM(Java Open Transaction Manager)是ObjectWeb的一個開源JTA實現(xiàn),它本身也是開源應用程序服務器JOnAS(Java Open Application Server)的一部分,為其提供JTA分布式事務的功能。
Spring 2.0附帶的依賴類庫中雖然包含jotm類庫,但是并不完整,你可以到http://jotm.objectweb.org下載完全版的JOTM。
Spring為JOTM提供了一個org.springframework.transaction.jta.JotmFactoryBean支持類,通過該支持類可以方便地創(chuàng)建JOTM本地實例。
下面,我們通過配置,使上節(jié)中BbtForumImpl#addTopic()方法工作在JTA事務的環(huán)境下。addTopic()內(nèi)部使用兩個DAO類(TopicDao和PostDao)分別訪問不同數(shù)據(jù)庫中的表。通過下面的步驟說明了使addTopic()方法擁有JTA事務的整個過程:
?
1. 將JOTM以下類庫添加到類路徑中:
jotm.jar
xapool.jar
jotm_jrmp_stubs.jar
jta-spec1_0_1.jar
connector-1_5.jar
2. 編寫JOTM配置文件,放到類路徑下
carol.properties
#JNDI調(diào)用協(xié)議
carol.protocols=jrmp
#不使用CAROL JNDI封裝器
carol.start.jndi=false
#不啟動命名服務器
carol.start.ns=false
3. 在MySQL上建立兩個數(shù)據(jù)庫
在MySQL數(shù)據(jù)庫中運行SQL腳本,建立topicdb和postdb兩個數(shù)據(jù)庫,在topicdb數(shù)據(jù)庫中創(chuàng)建t_topic表,在postdb數(shù)據(jù)庫中創(chuàng)建t_post表。我們希望在這兩個數(shù)據(jù)庫上進行JTA事務。SQL腳本如下所示:
DROP DATABASE IF EXISTS topicdb;
CREATE DATABASE topicdb DEFAULT CHARACTER SET utf8;
USE topicdb;
drop table if exists t_topic;
create table t_topic
(
topic_id int(11) not null auto_increment,
forum_id int(11) not null default 0,
topic_title varchar(100) not null default '',
user_id int(11) not null default 0,
topic_time datetime default NULL,
topic_views int(11) default 1,
topic_replies int(11) default 0,
primary key (topic_id)
);
create index IDX_TOPIC_USER_ID on t_topic
(
user_id
);
?
DROP DATABASE IF EXISTS postdb;
CREATE DATABASE postdb DEFAULT CHARACTER SET utf8;
USE postdb;
create table t_post
(
post_id int(11) not null auto_increment,
topic_id int(11) not null default 0,
forum_id int(11) not null default 0,
user_id int(11) not null default 0,
post_text text,
post_attach blob,
post_time datetime default NULL,
primary key (post_id)
);
create index IDX_POST_TOPIC_ID on t_post
(
topic_id
);
?
4. 在Spring配置文件中配置JOTM
代碼清單 1 applicationContext-jta.xml
…
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />①JOTM本地實例
②JTA事務管理器
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="jotm" /> ②-1:指定userTransaction屬性
</bean>
③XAPool配置,內(nèi)部包含了一個XA數(shù)據(jù)源,對應topicdb數(shù)據(jù)庫
<bean id="topicDS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
destroy-method="shutdown">
<property name="dataSource">
③-1:內(nèi)部XA數(shù)據(jù)源
<bean class="org.enhydra.jdbc.standard.StandardXADataSource"
destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="com.MySQL.jdbc.Driver" />
<property name="url" value="jdbc:MySQL://localhost:3309/topicdb" />
</bean>
</property>
<property name="user" value="root" />
<property name="password" value="1234" />
</bean>
④按照③相似的方式配置另一個XAPool,對應postdb數(shù)據(jù)庫,
?
<bean id="postDS" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource"
destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3309/postdb" />
</bean>
</property>
<property name="user" value="root" />
<property name="password" value="1234" />
</bean>
⑤配置訪問topicDB數(shù)據(jù)源的Spring JDBC模板
<bean id="topicTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="topicDS" />
</bean>
⑥配置訪問postDB數(shù)據(jù)源的Spring JDBC模板
<bean id="postTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="postDS" />
</bean>
⑦基于topicTemplate數(shù)據(jù)源的topicDao
<bean id="topicDao" class="com.baobaotao.dao.jdbc.TopicJdbcDao">
?
<property name="jdbcTemplate" ref="topicTemplate" />
</bean>
⑧基于postTemplate數(shù)據(jù)源的postDao
<bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao">
<property name="jdbcTemplate" ref="postTemplate" />
</bean>
⑨進行跨數(shù)據(jù)庫JTA事務的業(yè)務類
<bean id="bbtForum" class="com.baobaotao.service.impl.BbtForumImpl">
<property name="topicDao" ref="topicDao" />
<property name="postDao" ref="postDao" />
</bean>
⑩對BbtForumImpl業(yè)務類中的@Transaction注解進行驅(qū)動
<tx:annotation-driven transaction-manager="txManager" />
首 先,我們在①處通過Spring所提供的JotmFactoryBean創(chuàng)建一個本地JOTM實例,該實例同時實現(xiàn)了 javax.transaction.UserTransaction和javax.transaction.TransactionManager接 口,它可以和ObjectWeb的XAPool一起工作。
JTA事務管理器通過userTransaction屬性引用本地JOTM實例,Spring的JtaTransactionManager會自動探測 到傳入的javax.transaction.UserTransaction引用也實現(xiàn)了 javax.transaction.TransactionManager,所以我們無需再配置JtaTransactionManager的 transactionManager屬性,如②所示。
在Spring中配置JOTM的另一個關鍵問題是配置XAPool,支持JTA事務的數(shù)據(jù)源必須封裝成XAPool。首先,我們通過 org.enhydra.jdbc.standard.StandardXADataSource 配置一個XA數(shù)據(jù)源,它指向topicdb數(shù)據(jù)庫,如③-1所示。而后,通過 org.enhydra.jdbc.pool.StandardXAPoolDataSource將其封裝成一個XAPool,如③所示。按照相同的方 式,配置指向postdb數(shù)據(jù)庫的XAPool,如④所示。
?
接下來的配置就順理成章了,分別使用Spring JDBC的模板類配置DAO類,然后再配置引用DAO類的業(yè)務類。關于Spring JDBC的詳細內(nèi)容,參見第10章的內(nèi)容。
這里,我們使用@Transaction注解對業(yè)務類BbtForumImpl進行事務聲明,所以通過<tx:annotation-driven/>對此進行驅(qū)動,BbtForumImpl的代碼如下所示:
代碼清單 2 BbtForumImpl
package com.baobaotao.service.impl;
import org.springframework.transaction.annotation.Transactional;
import com.baobaotao.dao.PostDao;
import com.baobaotao.dao.TopicDao;
import com.baobaotao.domain.Forum;
import com.baobaotao.domain.Topic;
import com.baobaotao.service.BbtForum;
@Transactional ①事務注解,以便Spring動態(tài)織入事務管理功能
public class BbtForumImpl implements BbtForum ...{
private TopicDao topicDao;
private PostDao postDao;
public void addTopic(Topic topic) throws Exception ...{ ②將方法將被施加JTA事務的增強
topicDao.addTopic(topic);
postDao.addPost(topic.getPost());
}
}
BbtForumImpl將Dao類組織起來,PostDao和TopicDao分別訪問不同數(shù)據(jù)庫中表,通過Spring注解驅(qū)動事務切面的增強后,它們將工作于同一個JTA事務中。
5. 在Spring中運行測試
代碼清單 3 TestBbtForumJta
package com.baobaotao.service;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
…
public class TestBbtForumJta extends AbstractDependencyInjectionSpringContextTests...{
private BbtForum bbtForum;
private final Logger logger = Logger.getLogger(getClass());
public void setBbtForum(BbtForum bbtForum) ...{
this.bbtForum = bbtForum;
}
protected String[] getConfigLocations() ...{
return new String[]...{"classpath:applicationContext-jta.xml"};
}
public void testAddPost() throws Exception...{
logger.info("begin........");
Topic topic = new Topic();
topic.setTopicTitle("Title -pfb");
Post post = new Post();
post.setPostText("post content -pfb");
topic.setPost(post);
bbtForum.addTopic(topic); ①使用了JTA事務的業(yè)務方法
logger.info("end........");
}
}
?
通過Spring測試類AbstractDependencyInjectionSpringContextTests的支持,很容易編寫一個測試類, 對啟用了JTA事務的BbtForum#addTopic()方法進行測試。建議你將Log4J設置為DEBUG,這樣就可以通過豐富的輸出日志觀測到 JTA事務的執(zhí)行情況。運行這個測試類后,你將可以看到JTA事務被正確實施。
Spring引用Tomcat的 JTA事務
Tomcat是Servlet容器,但它提供了JNDI的實現(xiàn),因此用戶可以象在Java EE應用程序服務器中一樣,在Tomcat中使用JNDI查找JDBC數(shù)據(jù)源。在事務處理方面,Tomcat本身并不支持JTA,但是可以通過集成JOTM達到目的。
如果你的應用最終部署到一個功能齊備的Java EE應用服務器上,也許你更希望使用Java EE應用服務器的JTA功能,這樣可以利用應用服務器本身許多優(yōu)化措施。下面,我們讓Tomcat通過JNDI開放JOTM的JTA的數(shù)據(jù)源,進而在Spring容器引用這個JNDI數(shù)據(jù)源,并在此基礎上提供JTA事務。我們所使用的環(huán)境是:Tomcat 5.5+JOTM 2.3。
1. 添加所需的JAR文件
將JOTM以下類包添加到<Tomcat安裝目錄>/common/lib目錄中:
jotm.jar
jotm_jrmp_stubs.jar
jotm_iiop_stubs.jar
ow_carol.jar
jta-spec1_0_1.jar
jts1_0.jar
objectweb-datasource.jar
xapool.jar
howl.jar
connector-1_5.jar
同時,還需要添加相應數(shù)據(jù)庫的JDBC驅(qū)動類包,例如MySQL的mysql.jar。
2. 配置JOTM
新建一個carol.properties配置文件,放置到<Tomcat安裝目錄>/common/classes目錄下,配置文件內(nèi)容如下:
#JNDI調(diào)用協(xié)議
carol.protocols=jrmp
# 本地RMI調(diào)用
carol.jvm.rmi.local.call=true
?
# 不使用CAROL的JNDI封裝器
carol.start.jndi=false
# 不啟用命名服務器
carol.start.ns=false
# 命名工廠類
carol.jndi.java.naming.factory.url.pkgs=org.apache.naming
將carol.start.jndi設置為false,讓JOTM不使用CAROL JNDI wrapper,從而可以避免類裝載錯誤的發(fā)生。
3. 配置Tomcat環(huán)境,配置JNDI的數(shù)據(jù)源
在<Tomcat安裝目錄>/conf/context.xml文件中添加以下內(nèi)容:
<Resource name="jdbc/topicDS" auth="Container" type="javax.sql.DataSource" ①-1:JNDI數(shù)據(jù)源
factory="org.objectweb.jndi.DataSourceFactory"
username="root" password="1234"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3309/topicdb"
maxActive="30" maxIdle="30"/>
<Resource name="jdbc/postDS" auth="Container" type="javax.sql.DataSource" ①-2:JNDI數(shù)據(jù)源
factory="org.objectweb.jndi.DataSourceFactory"
username="root" password="1234"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3309/postdb"
maxActive="30" maxIdle="30"/>
②JOTM JTA事務管理
<Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/>
在Tomcat中配置兩個JNDI數(shù)據(jù)源,它們分別指向topicdb和postdb數(shù)據(jù)庫,如①處所示。最后配置JOTM的JTA事務管理器,該事務管理器自動對兩個JNDI中的數(shù)據(jù)源應用JTA事務。
?
4. Spring中相應的配置
讓應用服務器提供JNDI數(shù)據(jù)源管理和JTA事務后,Spring肩上的擔子減輕了許多,Spring要做的只是簡單地引用JNDI的數(shù)據(jù)源,并啟用JtaTransactionManager就可以了。
代碼清單 4 applicationContext-jta-tomcat.xml:使用應用服務器的JTA支持
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
①使用Tomcat JNDI的數(shù)據(jù)源
<jee:jndi-lookup id="topicDS" jndi-name="java:comp/env/jdbc/topicDS" />
<jee:jndi-lookup id="postDS" jndi-name="java:comp/env/jdbc/postDS" />
<bean id="topicTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="topicDS" />
</bean>
<bean id="postTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="postDS" />
</bean>
<bean id="topicDao" class="com.baobaotao.dao.jdbc.TopicJdbcDao">
<property name="jdbcTemplate" ref="topicTemplate" />
</bean>
<bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao">
<property name="jdbcTemplate" ref="postTemplate" />
</bean>
<bean id="bbtForum" class="com.baobaotao.service.impl.BbtForumImpl">
<property name="topicDao" ref="topicDao" />
<property name="postDao" ref="postDao" />
</bean>
②只需要指定一個JTA事務管理器就可以了,Spring會自動使用Tomcat中的JTA事務功能
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<tx:annotation-driven transaction-manager="txManager" />
</beans>
?
在①處,我們通過Spring jee命名空間提供的<jee:jndi-lookup>標簽獲取應用服務器中的JNDI資源,并將它們聲明為一個Bean以供持久化模板類引用。
和直接在Spring中使用JOTM不一樣,這時,我們僅需要簡單地配置一個JtaTransactionManager就可以了,該事務管理器將自動將JTA事務委托給應用程序器。
Spring引用Java EE應用服務器 JTA事務功能和 Tomcat+JOTM提供JTA事務功能的配置步驟基本相似,相信大家可以對照這個實例完成相應的配置。另外,這里的實例采用了Spring JDBC作為持久層實現(xiàn)技術,你完全可以通過少量的調(diào)整將其應用到JPA、Hibernate、iBatis等持久化實現(xiàn)技術中。
在特定應用服務器使用JTA
一般來說,Spring的事務抽象與應用服務器是無關的。不過,如果你如果希望事務管理器使用特定的UserTransaction 和 TransactionManager 對象(可以被自動探測),以獲取更多的增強事務語義。這時,針對不同的Java EE應用服務器,Spring的事務管理器可以采取不同的配置。
? BEA WebLogic
在一個使 用WebLogic 7.0、8.1或更高版本的環(huán)境中,你一般會優(yōu)先選用特定于WebLogic的 WebLogicJtaTransactionManager 類來取代基礎的 JtaTransactionManager 類,因為在WebLogic環(huán)境中,該類提供了對Spring事務定義的完全支持,超過了標準的JTA語義。你可以使用以下的配置達到目的:
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager"/>
它的特性包括:支持事務名,支持為每個事務定義隔離級別,以及在任何環(huán)境下正確地恢復事務的能力。
? IBM WebSphere
在WebSphere 5.1、5.0和4.x環(huán)境下,你可以使用Spring的 WebSphereTransactionManagerFactoryBean 類。這是一個工廠類,通過WebSphere的 靜態(tài)訪問方法(每個版本的WebSphere中都不同)獲取到JTA TransactionManager 實例。一旦通過工廠bean獲取到JTA TransactionManager 實例,就可以使用該實例裝配一個Spring的 JtaTransactionManager bean,它封裝了JTA UserTransaction,提供增強的事務語義。你可以按以下方式進行配置:
<bean id="wsJtaTm" class="org.springframework.transaction.jta.WebSphereTransactionManagerFactoryBean"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager ref="wsJtaTm"/>①引用WebSphere的JTA事務管理器
</bean>
小結(jié)
你既可以在沒有任務應用服務器支持的情況下,直接通過集成JOTM在Spring中使用JTA事務管理,也可以通過引用Java EE應用服務器的JNDI數(shù)據(jù)源,利用應用服務器提供的JTA事務功能間接實現(xiàn)Spring 中的JTA事務管理。為了利用一些高級Java EE應用服務器的JTA事務高級功能,你可以通過Spring所提供的特定于應用服務器的JTA事務管理器進行配置
原文地址http://www.bieryun.com/1849.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結(jié)
以上是生活随笔為你收集整理的在Spring中使用JTA事务管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 睡还是被睡,这是一个问题!
- 下一篇: Springmvc的handler me