全局事务是指在一个事务中涉及到几个事务参入者,这些事务参入者可以是我们常见的数据库操作,消息(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中配置如下:
3,Java代码:
4,示例需要发布到Weblogic中,访问BuzSingleService 的代码在一个servlet中如下:
5,配置web.xml如下:
6,在浏览器输入 http://localhost:7001/springWeb/xx.xawl,在两个数据库中正常插入数据.,如果将testTX1改为如下,两个数据库中都不会有数据插入.
对于声明型事务的一些提交回滚控制特性的其他介绍请参照 http://blog.youkuaiyun.com/kkdelta/article/details/7258050
二,如果代码不是在Weblogic容器中运行,如在standalone的main方法中,需要将weblogic.jar和xbean.jar加入到运行的classpath,Spring的配置如下(加入JNDIlookup的支持):
JAVA main方法代码:
*在使用过程中遇到的一些问题:
a,如果将Spring配置为default-autowire="byName",会有如下异常:
b,TransactionAwareDataSourceProxy让人很迷惑,开始以为是可以让不是在Weblogic上配置的DataSource也能自动参入到事务中,其实不是.
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>
- 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");
- }
- 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;
- }
- }
- <?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>
- db1jdbcDAO.testInsert(0, "db1jdbcDAO val0");
- db2jdbcDAO.testInsert(0, "db2jdbcDAO val0");
- String nullStr = null;
- nullStr.length();
二,如果代码不是在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>
- 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)
Spring文档的介绍是这个类可以让历史遗留代码的Datasource能够参入到事务中,就像是从JNDI得到Datasource一样,实际上不是.(一直没有弄明白)
三,DataSource不是在Weblogic上配置的话,Spring就只能起到一个提供Bean工厂的作用,为得到JTA transaction manager提供方便.
关于使用JTA编程的方式可以参照http://blog.youkuaiyun.com/kkdelta/article/details/5579142.
对于二和三的应用,在实际中应该用的很少了.