全局事务是指在一个事务中涉及到几个事务参入者,这些事务参入者可以是我们常见的数据库操作,消息(MQ)操作等等.如同时进行下面的操作,比如"转账"操作发生在两个数据库:
1,从数据库A的的表中将某个帐号的余额减少.
2从数据库B的的表中将某个帐号的余额增加.
3,提交在数据库A中的操作.
4,提交在数据库B中的操作.
通常单个数据库只能保证本数据库的事务要么提交要么回滚,当涉及的事务跨数据库的时候,就需要一个在两个数据库之间进行事务"协调"的事务管理器了,而数据库也需要为参入这种"协调"处理实现特殊协议,叫做XA或者两阶段提交协议.Java对这种全局事务管理是通过JTA规范来做的,通常就是begin,commit或者rollback的形式,本文通过示例简单介绍一下Spring利用Weblogic提供的JTA事务管理器管理全局事务.
*注意,如果用Spring的事务声明,WebLogicJtaTransactionManager只能管理在Weblogic通过DataSource配置的数据库操作,或者在Weblogic上配置的JMS.(但是也没有找到官方文档这样明确的说明过,本人在使用的过程中曾经尝试将不是从Weblogic上配置的XADataSource中进行的数据库操作,以及通过ActiveMQ的ActiveMQXAConnectionFactory操作JSM声明为Spring利用WebLogicJtaTransactionManager,发现行不通.如果有这种需求的话,可以使用atomikos或者jotm来实现)
下面简单介绍一下Spring和WebLogicJtaTransactionManager结合使用的一些应用:一,用到Spring的事务声明,应用在Weblogic容器中运行,二,用到Spring的事务声明,应用不是在Weblogic容器中运行,三,没有用到Spring的事务声明.
一应用在Weblogic容器中运行:
1,在Weblogic上配置连接到两个不同数据库的DataSource,需要DataSource支持XA.
2,在Spring中配置如下:
二,如果代码不是在Weblogic容器中运行,如在standalone的main方法中,需要将weblogic.jar和xbean.jar加入到运行的classpath,Spring的配置如下(加入JNDIlookup的支持):
a,如果将Spring配置为default-autowire="byName",会有如下异常:
Spring文档的介绍是这个类可以让历史遗留代码的Datasource能够参入到事务中,就像是从JNDI得到Datasource一样,实际上不是.(一直没有弄明白)
三,DataSource不是在Weblogic上配置的话,Spring就只能起到一个提供Bean工厂的作用,为得到JTA transaction manager提供方便.
关于使用JTA编程的方式可以参照http://blog.youkuaiyun.com/kkdelta/article/details/5579142.
对于二和三的应用,在实际中应该用的很少了.
1,从数据库A的的表中将某个帐号的余额减少.
2从数据库B的的表中将某个帐号的余额增加.
3,提交在数据库A中的操作.
4,提交在数据库B中的操作.
通常单个数据库只能保证本数据库的事务要么提交要么回滚,当涉及的事务跨数据库的时候,就需要一个在两个数据库之间进行事务"协调"的事务管理器了,而数据库也需要为参入这种"协调"处理实现特殊协议,叫做XA或者两阶段提交协议.Java对这种全局事务管理是通过JTA规范来做的,通常就是begin,commit或者rollback的形式,本文通过示例简单介绍一下Spring利用Weblogic提供的JTA事务管理器管理全局事务.
*注意,如果用Spring的事务声明,WebLogicJtaTransactionManager只能管理在Weblogic通过DataSource配置的数据库操作,或者在Weblogic上配置的JMS.(但是也没有找到官方文档这样明确的说明过,本人在使用的过程中曾经尝试将不是从Weblogic上配置的XADataSource中进行的数据库操作,以及通过ActiveMQ的ActiveMQXAConnectionFactory操作JSM声明为Spring利用WebLogicJtaTransactionManager,发现行不通.如果有这种需求的话,可以使用atomikos或者jotm来实现)
下面简单介绍一下Spring和WebLogicJtaTransactionManager结合使用的一些应用:一,用到Spring的事务声明,应用在Weblogic容器中运行,二,用到Spring的事务声明,应用不是在Weblogic容器中运行,三,没有用到Spring的事务声明.
一应用在Weblogic容器中运行:
1,在Weblogic上配置连接到两个不同数据库的DataSource,需要DataSource支持XA.
2,在Spring中配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
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-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="appContextProvider" class="com.test.spring.tx.util.ApplicationContextProvider" />
<bean id="db1jdbcDAO" class="com.test.spring.tx.xawl.DB1jdbcDAO">
<property name="dataSource" ref="dataSource1" />
</bean>
<bean id="db2jdbcDAO" class="com.test.spring.tx.xawl.DB2jdbcDAO">
<property name="dataSource" ref="dataSource2" />
</bean>
<bean id="dataSource1"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>ds89</value>
</property>
</bean>
<bean id="dataSource2"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>DSORCL</value>
</property>
</bean>
<bean id="buzSingleService" class="com.test.spring.tx.xawl.BuzSingleService">
<property name="db1jdbcDAO" ref="db1jdbcDAO" />
<property name="db2jdbcDAO" ref="db2jdbcDAO" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" >
<property name="transactionManagerName" value="javax.transaction.TransactionManager" />
</bean>
<!-- you can also use JtaTransactionManager
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
<property name="userTransactionName">
<value>weblogic/transaction/UserTransaction</value>
</property>
</bean>
-->
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.test.spring.tx.xawl.*Service*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
</beans>
3,Java代码:public class DB1jdbcDAO {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void testInsert(int id, String val) {
this.jdbcTemplate.update("insert into A (ID, VAL) values (?, ?)", id, val);
}
public class BuzSingleService {
DB1jdbcDAO db1jdbcDAO;
DB2jdbcDAO db2jdbcDAO;
public void testTX1() throws Exception {
db1jdbcDAO.testInsert(0, "db1jdbcDAO val0");
db2jdbcDAO.testInsert(0, "db2jdbcDAO val0");
}
4,示例需要发布到Weblogic中,访问BuzSingleService 的代码在一个servlet中如下:public class XawlTestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("accessed:" + new Date());
PrintWriter pw = response.getWriter();
BuzSingleService serv = (BuzSingleService) ApplicationContextProvider.getApplicationContext().getBean(
"buzSingleService");
try {
serv.testTX1();
} catch (Exception e) {
e.printStackTrace();
pw.println(e.getMessage());
}
pw.println("Http response from XawlTestServlet");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
doGet(request, response);
}
}
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx;
public static ApplicationContext getApplicationContext() {
return ctx;
}
public void setApplicationContext(ApplicationContext appCtx) throws BeansException {
ApplicationContextProvider.ctx=appCtx;
}
}
5,配置web.xml如下:<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>
prjSptx</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/xawlAppcontext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>xawl</servlet-name>
<servlet-class>
com.test.spring.tx.servlet.XawlTestServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>xawl</servlet-name>
<url-pattern>*.xawl</url-pattern>
</servlet-mapping>
</web-app>
6,在浏览器输入 http://localhost:7001/springWeb/xx.xawl,在两个数据库中正常插入数据.,如果将testTX1改为如下,两个数据库中都不会有数据插入. db1jdbcDAO.testInsert(0, "db1jdbcDAO val0");
db2jdbcDAO.testInsert(0, "db2jdbcDAO val0");
String nullStr = null;
nullStr.length();
对于声明型事务的一些提交回滚控制特性的其他介绍请参照 http://blog.youkuaiyun.com/kkdelta/article/details/7258050二,如果代码不是在Weblogic容器中运行,如在standalone的main方法中,需要将weblogic.jar和xbean.jar加入到运行的classpath,Spring的配置如下(加入JNDIlookup的支持):
<bean id="db1jdbcDAO" class="com.test.spring.tx.xawl.DB1jdbcDAO">
<property name="dataSource" ref="dataSource1" />
</bean>
<bean id="db2jdbcDAO" class="com.test.spring.tx.xawl.DB2jdbcDAO">
<property name="dataSource" ref="dataSource2" />
</bean>
<bean id="dataSource1"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref local="jndiTemplate" />
</property>
<property name="jndiName">
<value>ds89</value>
</property>
</bean>
<bean id="dataSource2"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref local="jndiTemplate" />
</property>
<property name="jndiName">
<value>DSORCL</value>
</property>
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">
weblogic.jndi.WLInitialContextFactory
</prop>
<prop key="java.naming.provider.url">t3://localhost:7001</prop>
</props>
</property>
</bean>
<bean id="buzSingleService" class="com.test.spring.tx.xawl.BuzSingleService">
<property name="db1jdbcDAO" ref="db1jdbcDAO" />
<property name="db2jdbcDAO" ref="db2jdbcDAO" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
<property name="jndiTemplate">
<ref local="jndiTemplate" />
</property>
<property name="userTransactionName">
<value>weblogic/transaction/UserTransaction</value>
</property>
</bean>
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.test.spring.tx.xawl.*Service*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
JAVA main方法代码: ApplicationContext ctx = new ClassPathXmlApplicationContext("config/xawlStandaloneAppcontext.xml");
BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");
try {
serv.testTX1();
*在使用过程中遇到的一些问题:a,如果将Spring配置为default-autowire="byName",会有如下异常:
java.lang.IllegalStateException: Cannot convert value of type [org.springframework.transaction.jta.JtaTransactionManager] to
required type [javax.transaction.TransactionManager] for property 'transactionManager': no matching editors or
conversion strategy found at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:289)
b,TransactionAwareDataSourceProxy让人很迷惑,开始以为是可以让不是在Weblogic上配置的DataSource也能自动参入到事务中,其实不是.Spring文档的介绍是这个类可以让历史遗留代码的Datasource能够参入到事务中,就像是从JNDI得到Datasource一样,实际上不是.(一直没有弄明白)
三,DataSource不是在Weblogic上配置的话,Spring就只能起到一个提供Bean工厂的作用,为得到JTA transaction manager提供方便.
关于使用JTA编程的方式可以参照http://blog.youkuaiyun.com/kkdelta/article/details/5579142.
对于二和三的应用,在实际中应该用的很少了.