A global transaction involves several Transaction participants. These transaction participants can be common database operations, message (MQ) operations, and so on. if you perform the following operations at the same time, for example, the "transfer" Operation occurs in two databases:
1. Reduce the balance of an account from the table of database.
2. Increase the balance of an account from the table of database B.
3. Submit the operation in database.
4. Submit the operation in database B.
Generally, a single database can only ensure that the transactions in the database are either committed or rolled back. When the transactions involved are cross-database, A transaction manager for "Coordinating" transactions between two databases is required, and the database also needs to implement special protocols for such "Coordinating" processing, it is called XA or a two-phase commit protocol. java manages such global transactions through the JTA specification, usually in the form of begin, commit, or rollback, this article uses examples to briefly introduce how spring manages global transactions using the JTA Transaction Manager provided by weblogic.
* Note: If the Spring transaction declaration is used, weblogicjtatransactionmanager can only manage database operations configured on WebLogic through datasource, or JMS configured on weblogic. (However, I have not found such a clear description in the official documentation. I tried to operate databases that are not configured from the xadatasource on weblogic, and activemq activemqxaconnectionfactory to operate JSM Declaration for spring using weblogicjtatransactionmanager, found that it does not work. if you have such requirements, you can use atomikos or jotm)
The following briefly introduces some applications used by spring and weblogicjtatransactionmanager in combination: 1. Use spring's transaction declaration to run the application in the Weblogic container. 2. Use spring's transaction declaration, the application is not running in the Weblogic container. 3. The Spring transaction statement is not used.
1. It should be used in WebLogic containers:
1. Configure datasource to connect to two different databases on weblogic. datasource must support Xa.
2. Configure the following in 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 code:
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. The example needs to be published to weblogic. The code for accessing the buzsingleservice is as follows in a 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. Configure web. XML as follows:
<?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. Enter http: // localhost: 7001/springweb/XX in the browser. xawl, which normally inserts data into two databases ., if you change testtx1 to the following, no data is inserted in both databases.
db1jdbcDAO.testInsert(0, "db1jdbcDAO val0"); db2jdbcDAO.testInsert(0, "db2jdbcDAO val0"); String nullStr = null; nullStr.length();
For additional descriptions of some commit rollback control features of declarative transactions, refer to the http://blog.csdn.net/kkdelta/article/details/7258050
2. If the code is not run in the Weblogic container, for example, in the main method of standalone, you need to set weblogic. jar and xbean. jar is added to the running classpath. The spring configuration is as follows (supported by 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 method code:
ApplicationContext ctx = new ClassPathXmlApplicationContext("config/xawlStandaloneAppcontext.xml"); BuzSingleService serv =(BuzSingleService)ctx.getBean("buzSingleService"); try { serv.testTX1();
* Problems encountered during use:
A. If spring is set to default-autowire = "byname", the following exception occurs:
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 is confusing. In the beginning, it was thought that datasource not configured on WebLogic could also be automatically involved in the transaction, but it was not.
The spring document introduces this class to enable the datasource of the historical code to be involved in the transaction, just like getting datasource from JNDI, not actually. (I have never figured it out)
3. If datasource is not configured on WebLogic, spring can only serve as a bean factory, providing convenience for JTA Transaction Manager.
For how to use JTA programming, refer to the http://blog.csdn.net/kkdelta/article/details/5579142.
The second and third applications should be rarely used in practice.