一、前言
相信大家对分布式系统多少有点接触,一个大型的互联网体系平台 往往有一系列的分布式系统构建而成,对于完成实现一个用户业务请求响应,往往伴随n个服务的重叠和n个数据库的数据状态的刷新,因此对于这种用例场景,传统单应用或关系型数据事务无法保证数据“一致性”或状态同步等等要求,这边主要通过weblogic实现JTA(Java Transaction API)接口实现容器来示例数据一致性(主流的WebLogic、websphere等都提供了JTA的实现和支持,Tomcat借助第三方的框架Jotm、Automikos等来实现,两者均支持spring事务整合),完整项目源码下载或依赖包跳转相关页面(download)。
二、实践步骤
1. 分别在weblogic配置两个独立数据源分别对应不同的用户数据库,注意在配置数据源的时候,驱动初选择对应的版本外,还需要选择支持XA协议(它是TM(事务管理器)和RM(资源管理器)之间的接口)的驱动
2. 在spring配置注册不同的数据源和相关配置,如下所示
<?xml version="1.0" encoding="UTF-8"?>@b@<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">@b@<beans>@b@ <!-- JNDI数据源 -->@b@ <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">@b@ </bean>@b@ <bean id="dataSource"@b@ class="org.springframework.jndi.JndiObjectFactoryBean"> @b@ <property name="jndiName" value="jndi/utx" />@b@ <property name="jndiTemplate"><ref bean="jndiTemplate"/></property>@b@ </bean>@b@ <bean id="dataSource2"@b@ class="org.springframework.jndi.JndiObjectFactoryBean"> @b@ <property name="jndiName" value="jndi/utx2" />@b@ <property name="jndiTemplate"><ref bean="jndiTemplate"/></property>@b@ </bean>@b@ <bean id="jdbcTemplate"@b@ class="org.springframework.jdbc.core.JdbcTemplate">@b@ <property name="dataSource">@b@ <ref local="dataSource" />@b@ </property>@b@ </bean>@b@ <bean id="jdbcTemplate2"@b@ class="org.springframework.jdbc.core.JdbcTemplate">@b@ <property name="dataSource">@b@ <ref local="dataSource2" />@b@ </property>@b@ </bean>@b@</beans>
3. 数据操作工具类,分别删除uat1表tab_1和uat2表tab_2记录id分别为1、2的记录,工具类如下
import org.springframework.jdbc.core.JdbcTemplate;@b@import com.xwood.utx.util.SpringBeans;@b@@b@public class UtxDaoUtils {@b@ private static JdbcTemplate dbs=(JdbcTemplate)SpringBeans.getBean("jdbcTemplate");@b@ private static JdbcTemplate dbs2=(JdbcTemplate)SpringBeans.getBean("jdbcTemplate2");@b@ public static void delTab1(){@b@ String sql = "delete from tab_1 where id = ?";@b@ Object[] values = new Object[] { 1 };@b@ dbs.update(sql, values);@b@ }@b@ public static void delTab2(){@b@ String sql = "delete from tab_2 where id = ?";@b@ Object[] values = new Object[] { 2 };@b@ dbs2.update(sql, values);@b@ }@b@}
4. 获取weblogic容器分布式事务对象,调用工具类内容如下
import javax.naming.Context;@b@import javax.naming.InitialContext;@b@import javax.naming.NamingException;@b@import javax.transaction.SystemException;@b@import javax.transaction.UserTransaction;@b@@b@public class UserBeaTransaction {@b@ public static UserTransaction getUserTransaction() throws NamingException,SystemException {@b@ UserTransaction trans = null;@b@ Context ctx = new InitialContext();@b@ trans = (UserTransaction) ctx.lookup("java:comp/UserTransaction");//Bea默认注册名@b@ if (trans != null){@b@ trans.setTransactionTimeout(30*20); // 设置事务超时间@b@ return trans;@b@ }else{@b@ return null;@b@ }@b@ }@b@}
备注其他容器注册名,如下
* "java:comp/UserTransaction" for Resin 2.x, Oracle OC4J (Orion), JOnAS (JOTM), BEA WebLogic
* "java:comp/TransactionManager" for Resin 3.x
* "java:appserver/TransactionManager" for GlassFish
* "java:pm/TransactionManager" for Borland Enterprise Server and Sun Application Server (Sun ONE 7 and later)
* "java:/TransactionManager" for JBoss Application Server
5. 下面是配置一个简单的servlet的测试类,并在执行两个数据库删除操作动作之前,模拟抛出个运行异常
import java.io.IOException;@b@import javax.servlet.ServletException;@b@import javax.servlet.http.HttpServlet;@b@import javax.servlet.http.HttpServletRequest;@b@import javax.servlet.http.HttpServletResponse;@b@import javax.transaction.UserTransaction;@b@@b@import com.xwood.utx.service.UtxDaoUtils;@b@@b@public class UserActionServlet extends HttpServlet {@b@@b@ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {@b@ // TODO Auto-generated method stub@b@ doPost(request,response);@b@ }@b@ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {@b@ UserTransaction ut =null;@b@ try {@b@ ut = UserBeaTransaction.getUserTransaction();@b@ ut.begin();@b@ UtxDaoUtils.delTab1();@b@ throwException();//模拟发送异常@b@ UtxDaoUtils.delTab2();@b@ System.out.println("exception...");@b@ ut.commit();@b@ } catch (Exception e) {@b@ try {@b@ ut.rollback();@b@ System.out.println("rollback...");@b@ } catch (Exception e1) {@b@ // TODO Auto-generated catch block@b@ e1.printStackTrace();@b@ } @b@ }@b@ }@b@ private void throwException() throws RuntimeException{@b@ throw new RuntimeException();@b@ }@b@}
6. 浏览器执行用户请求,进行测试,结果事务成功发射回滚,保证数据同步,如下图
7. 项目完整的源码或依赖包跳转到下载页