什么是分布式事务?在网上找了一段比较容易理解的"定义".
分布式事务是指事务的参与者、支持事务的服务器、资源管理器以及事务管理器分别位于分布系统的不同节点之上,在两个或多个网络计算机资源上访问并且更新数据,将两个或多个网络计算机的数据进行的多次操作作为一个整体进行处理。如不同银行账户之间的转账。
对于在项目中接触到JTA,大部分的原因是因为在项目中需要操作多个数据库,同时,可以保证操作的原子性,保证对多个数据库的操作一致性。
在正式的项目中应该用springMVC(struts)+spring+hibernate(jpa)+jta,目前,先用spring+jta来完成基本的测试框架。下面我们看看代码
applicationContext-jta.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- jotm 本地实例 --> <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" /> <!-- JTA事务管理器 --> <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm"></property> </bean> <!-- XAPool配置,内部包含了一个XA数据源,对应sshdb数据库 --> <bean id="db1" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"> <property name="dataSource"> <!-- 内部XA数据源 --> <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://192.168.1.28:3306/sshdb?useUnicode=true&characterEncoding=UTF-8" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <!-- 另一个XAPool配置,内部包含另一个XA数据源,对应babasport数据库 --> <bean id="db2" 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://192.168.1.28:3306/babasport?useUnicode=true&characterEncoding=UTF-8" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <!-- 配置访问sshdb数据源的Spring JDBC模板 --> <bean id="sshdbTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="db1"></property> </bean> <!-- 配置访问babasport数据源的Spring JDBC模板 --> <bean id="babasportTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="db2"></property> </bean> </beans>
小注一下:spring-tx-3.2.4.jar里面竟然没有org.springframework.transaction.jta.JotmFactoryBean类,如果你可以选择spring-tx-2.5.6.jar,或者自己建立一下这个类。
接下来,看下dao层测试的代码
@Resource(name = "txManager") private JtaTransactionManager txManager; protected JdbcTemplate babasport_jdbcTemplate; /** * sshdb sql jdbcTemplate */ protected JdbcTemplate ssh_jdbcTemplate; /** * babasport sql jdbcTemplate * * @return */ public JdbcTemplate getBabasport_jdbcTemplate() { return babasport_jdbcTemplate; } public JdbcTemplate getSsh_jdbcTemplate() { return ssh_jdbcTemplate; } @Resource(name = "babasportTemplate") public void setBabasport_jdbcTemplate(JdbcTemplate babasport_jdbcTemplate) { this.babasport_jdbcTemplate = babasport_jdbcTemplate; } @Resource(name = "sshdbTemplate") public void setSsh_jdbcTemplate(JdbcTemplate ssh_jdbcTemplate) { this.ssh_jdbcTemplate = ssh_jdbcTemplate; } /** * 同时修改两个数据库的表中内容 * * @throws RollbackException */ public void updateMultiple() { if (null == this.txManager) { System.out.println("txManager为空"); return; } UserTransaction userTx = this.txManager.getUserTransaction(); if (null == userTx) { System.out.println("userTx为空"); return; } try { userTx.begin(); this.ssh_jdbcTemplate .execute("update wyuser set password='wangyong1' where id=8"); this.babasport_jdbcTemplate .execute("update brand set name='wangyong28' where code='14ac8d5b-d19c-40e9-97ea-d82dfbcd84c6'"); userTx.commit(); } catch (Exception e) { System.out.println("捕获到异常,进行回滚" + e.getMessage()); e.printStackTrace(); try { userTx.rollback(); } catch (IllegalStateException e1) { System.out.println("IllegalStateException:" + e1.getMessage()); } catch (SecurityException e1) { System.out.println("SecurityException:" + e1.getMessage()); } catch (SystemException e1) { System.out.println("SystemException:" + e1.getMessage()); } // System.out.println("sql语句操作失败"); } }
如果,将后一条update语句故意写错,就会发现会执行rollback,同时,对上面一个语句的操作也不会生效。基本的简单框架就是这样。