Spring全局事务之WebLogicJtaTransactionManager

来源:互联网 发布:github网站源码 编辑:程序博客网 时间:2024/06/16 16:31
全局事务是指在一个事务中涉及到几个事务参入者,这些事务参入者可以是我们常见的数据库操作,消息(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中配置如下:
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:p="http://www.springframework.org/schema/p"  
  5.     xmlns:aop="http://www.springframework.org/schema/aop"  
  6.     xmlns:tx="http://www.springframework.org/schema/tx"  
  7.     xmlns:jee="http://www.springframework.org/schema/jee"  
  8.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  9.     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
  10.     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
  11.     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd  
  12.     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
  13.     <bean id="appContextProvider" class="com.test.spring.tx.util.ApplicationContextProvider" />  
  14.     <bean id="db1jdbcDAO" class="com.test.spring.tx.xawl.DB1jdbcDAO">  
  15.         <property name="dataSource" ref="dataSource1" />  
  16.     </bean>  
  17.     <bean id="db2jdbcDAO" class="com.test.spring.tx.xawl.DB2jdbcDAO">  
  18.         <property name="dataSource" ref="dataSource2" />  
  19.     </bean>  
  20.     <bean id="dataSource1"    
  21.         class="org.springframework.jndi.JndiObjectFactoryBean">    
  22.         <property name="jndiName">    
  23.             <value>ds89</value>    
  24.         </property>    
  25.     </bean>  
  26.     <bean id="dataSource2"    
  27.         class="org.springframework.jndi.JndiObjectFactoryBean">    
  28.         <property name="jndiName">    
  29.             <value>DSORCL</value>    
  30.         </property>    
  31.     </bean>       
  32.     <bean id="buzSingleService" class="com.test.spring.tx.xawl.BuzSingleService">  
  33.         <property name="db1jdbcDAO" ref="db1jdbcDAO" />  
  34.         <property name="db2jdbcDAO" ref="db2jdbcDAO" />  
  35.     </bean>      
  36.     <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  37.         <tx:attributes>  
  38.             <tx:method name="*" propagation="REQUIRED"/>  
  39.         </tx:attributes>  
  40.     </tx:advice>  
  41.     <bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" >  
  42.         <property name="transactionManagerName" value="javax.transaction.TransactionManager" />         
  43.     </bean>  
  44.     <!-- you can also use JtaTransactionManager  
  45.      <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >  
  46.         <property name="userTransactionName">  
  47.          <value>weblogic/transaction/UserTransaction</value>  
  48.         </property>  
  49.       </bean>  
  50.     -->  
  51.     <aop:config>  
  52.         <aop:pointcut id="serviceOperation"  
  53.             expression="execution(* com.test.spring.tx.xawl.*Service*.*(..))" />  
  54.         <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />  
  55.     </aop:config>      
  56. </beans>  
3,Java代码:
[java] view plaincopy
  1. public class DB1jdbcDAO {  
  2.     private JdbcTemplate jdbcTemplate;      
  3.     public void setDataSource(DataSource dataSource) {  
  4.         this.jdbcTemplate = new JdbcTemplate(dataSource);  
  5.     }  
  6.     public void testInsert(int id, String val) {          
  7.         this.jdbcTemplate.update("insert into A (ID, VAL) values (?, ?)", id, val);  
  8.     }  
  9.   
  10. public class BuzSingleService {  
  11.     DB1jdbcDAO db1jdbcDAO;  
  12.     DB2jdbcDAO db2jdbcDAO;  
  13.     public void testTX1() throws Exception {  
  14.         db1jdbcDAO.testInsert(0"db1jdbcDAO val0");  
  15.         db2jdbcDAO.testInsert(0"db2jdbcDAO val0");  
  16.     }  
4,示例需要发布到Weblogic中,访问BuzSingleService 的代码在一个servlet中如下:
[java] view plaincopy
  1. public class XawlTestServlet extends HttpServlet {  
  2.     public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {  
  3.         System.out.println("accessed:" + new Date());  
  4.         PrintWriter pw = response.getWriter();  
  5.         BuzSingleService serv = (BuzSingleService) ApplicationContextProvider.getApplicationContext().getBean(  
  6.                 "buzSingleService");  
  7.         try {  
  8.             serv.testTX1();  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.             pw.println(e.getMessage());              
  12.         }  
  13.         pw.println("Http response from XawlTestServlet");  
  14.     }  
  15.     public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {  
  16.         doGet(request, response);  
  17.     }  
  18. }  
  19. public class ApplicationContextProvider implements ApplicationContextAware {  
  20.     private static ApplicationContext ctx;  
  21.     public static ApplicationContext getApplicationContext() {  
  22.         return ctx;  
  23.     }  
  24.     public void setApplicationContext(ApplicationContext appCtx) throws BeansException {  
  25.         ApplicationContextProvider.ctx=appCtx;  
  26.     }  
  27. }  
5,配置web.xml如下:
[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  5.     <display-name>  
  6.     prjSptx</display-name>  
  7.     <welcome-file-list>  
  8.         <welcome-file>index.html</welcome-file>  
  9.     </welcome-file-list>      
  10.     <context-param>      
  11.         <param-name>contextConfigLocation</param-name>  
  12.         <param-value>  
  13.             classpath:config/xawlAppcontext.xml  
  14.         </param-value>  
  15.     </context-param>  
  16.       <listener>  
  17.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  18.       </listener>      
  19.   <servlet>  
  20.     <servlet-name>xawl</servlet-name>  
  21.     <servlet-class>  
  22.             com.test.spring.tx.servlet.XawlTestServlet  
  23.         </servlet-class>  
  24.     <load-on-startup>1</load-on-startup>  
  25.   </servlet>  
  26.   <servlet-mapping>  
  27.     <servlet-name>xawl</servlet-name>  
  28.     <url-pattern>*.xawl</url-pattern>  
  29.   </servlet-mapping>  
  30. </web-app>  
6,在浏览器输入 http://localhost:7001/springWeb/xx.xawl,在两个数据库中正常插入数据.,如果将testTX1改为如下,两个数据库中都不会有数据插入.
[java] view plaincopy
  1. db1jdbcDAO.testInsert(0"db1jdbcDAO val0");  
  2. db2jdbcDAO.testInsert(0"db2jdbcDAO val0");  
  3. String nullStr = null;  
  4. nullStr.length();  
对于声明型事务的一些提交回滚控制特性的其他介绍请参照 http://blog.csdn.net/kkdelta/article/details/7258050
二,如果代码不是在Weblogic容器中运行,如在standalone的main方法中,需要将weblogic.jar和xbean.jar加入到运行的classpath,Spring的配置如下(加入JNDIlookup的支持):
[html] view plaincopy
  1. <bean id="db1jdbcDAO" class="com.test.spring.tx.xawl.DB1jdbcDAO">  
  2.         <property name="dataSource" ref="dataSource1" />  
  3.     </bean>  
  4.     <bean id="db2jdbcDAO" class="com.test.spring.tx.xawl.DB2jdbcDAO">  
  5.         <property name="dataSource" ref="dataSource2" />  
  6.     </bean>  
  7.     <bean id="dataSource1"    
  8.         class="org.springframework.jndi.JndiObjectFactoryBean">    
  9.         <property name="jndiTemplate">  
  10.              <ref local="jndiTemplate" />  
  11.         </property>           
  12.         <property name="jndiName">    
  13.             <value>ds89</value>    
  14.         </property>    
  15.     </bean>  
  16.     <bean id="dataSource2"    
  17.         class="org.springframework.jndi.JndiObjectFactoryBean">  
  18.         <property name="jndiTemplate">  
  19.              <ref local="jndiTemplate" />  
  20.         </property>    
  21.         <property name="jndiName">    
  22.             <value>DSORCL</value>    
  23.         </property>    
  24.     </bean>  
  25.     <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">  
  26.         <property name="environment">  
  27.            <props>  
  28.               <prop key="java.naming.factory.initial">  
  29.                 weblogic.jndi.WLInitialContextFactory  
  30.               </prop>  
  31.               <prop key="java.naming.provider.url">t3://localhost:7001</prop>  
  32.            </props>  
  33.          </property>  
  34.       </bean>  
  35.              
  36.     <bean id="buzSingleService" class="com.test.spring.tx.xawl.BuzSingleService">  
  37.         <property name="db1jdbcDAO" ref="db1jdbcDAO" />  
  38.         <property name="db2jdbcDAO" ref="db2jdbcDAO" />  
  39.     </bean>      
  40.     <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  41.         <tx:attributes>  
  42.             <tx:method name="*" propagation="REQUIRED"/>  
  43.         </tx:attributes>  
  44.     </tx:advice>  
  45.      <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" >  
  46.          <property name="jndiTemplate">  
  47.              <ref local="jndiTemplate" />  
  48.         </property>  
  49.         <property name="userTransactionName">  
  50.          <value>weblogic/transaction/UserTransaction</value>  
  51.         </property>  
  52.       </bean>  
  53.     <aop:config>  
  54.         <aop:pointcut id="serviceOperation"  
  55.             expression="execution(* com.test.spring.tx.xawl.*Service*.*(..))" />  
  56.         <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />  
  57.     </aop:config>  
JAVA main方法代码:
[java] view plaincopy
  1. ApplicationContext ctx = new ClassPathXmlApplicationContext("config/xawlStandaloneAppcontext.xml");  
  2. BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService");  
  3. try {  
  4.     serv.testTX1();  
*在使用过程中遇到的一些问题:
a,如果将Spring配置为default-autowire="byName",会有如下异常:
[plain] view plaincopy
  1. java.lang.IllegalStateException: Cannot convert value of type [org.springframework.transaction.jta.JtaTransactionManager] to   
  2. required type [javax.transaction.TransactionManager] for property 'transactionManager': no matching editors or   
  3. 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.csdn.net/kkdelta/article/details/5579142.
对于二和三的应用,在实际中应该用的很少了.
0 0
原创粉丝点击