Spring3.2+mybatis3.0+atomikos的jta系统搭建

来源:互联网 发布:玛泽会计师事务所 知乎 编辑:程序博客网 时间:2024/05/18 01:31

我们有一个后台的项目,是用了好几个数据库链接,以前为了方便就用了多数据源的那种配置方法(不要吐槽呢),但是现在用户多了,经常会遇到不同数据库插入失败的问题。在我们当初使用这种架构的时候,就知道如果用这个框架会存在跨数据库事务无法处理,项目急呢。

现在有时间了,就准备处理一下这个遗留的bug,因为我们现在的框架用的是spring3.2+mybatis3.0,刚开始准备用jta中jotm来实现,结果在junitTest一直报org.springframework.transaction.jta.JotmFactoryBean  这个类找不到,后来查了一下spring的官方文档,原来Spring 3以上版本,去掉了JotmFactoryBean类,不能通过集成Jotm实现Jta功能,哎,只能怪我急攻心切,当时多查查文档也就不至于这样了,有多学了点知识呢,嘿嘿。现在只好用另一种形式了:atomikos,幸亏基本上都差不多呢。

其实在写这个系统的时候,我也在网上找了不少资料,但是大部分的都是只用了spring2,或者mybatis3,于是我就想写一个基于spring3+mybatis3的系统,方便大家互相学习呢,我第一次写博客,语言逻辑有问题的还请大家多多见谅呢。

1.数据库

在这里我用的是mysql的,新建了两个数据库分别为da1,da2

create database da1;use da1;CREATE TABLE `table1` (  `id` int(11) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
create database da2;use da2;CREATE TABLE `table2` (  `id` int(11) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.系统


2.1项目包截图

2.2基本类

在这里我只展示了其中的一个model实体类Table1.java,Table2和这个差不多

/**    * @文件名称: Tabel1.java * @类路径: com.kasiait.jta.da1.model * @描述: TODO * @作者:kasiait521 * @时间:2014-04-24 */package com.kasiait.jta.da1.model;import com.kasiait.jta.common.model.CommonPage;public class Tabel1 {private Integer id;//自增长idprivate CommonPage page;//这个是我们系统中用来分页的,大家可以忽略呢public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public CommonPage getPage() {return page;}public void setPage(CommonPage page) {this.page = page;}}

在这里我只展示了其中的一个mapper类Tabel1Mapper.java,Table2Mapper和这个差不多

/**    * @文件名称: Tabel1Mapper.java * @类路径: com.kasiait.jta.da1.mapper * @描述: TODO * @作者:kasiait521 * @时间:2014-04-24 */package com.kasiait.jta.da1.mapper;import java.util.List;import com.kasiait.jta.da1.model.Tabel1;public interface Tabel1Mapper {public void insertTabel1(Tabel1 t);public List<Tabel1> listPageAll(Tabel1 t);}

service类Tabel1Service.java

/**    * @文件名称: Tabel1Service.java * @类路径: com.kasiait.jta.da1.service * @描述: TODO * @作者:kasiait521 * @时间:2014-04-24 */package com.kasiait.jta.da1.service;import java.util.List;import com.kasiait.jta.da1.model.Tabel1;public interface Tabel1Service {public void insertTabel1(Tabel1 t);public List<Tabel1> listPageAll(Tabel1 t);}
serviceImpl类

/**    * @文件名称: Tabel1ServiceImpl.java * @类路径: com.kasiait.jta.da1.service.impl * @描述: TODO * @作者:kasiait521 * @时间:2014-04-24 */package com.kasiait.jta.da1.service.impl;import java.util.List;import com.kasiait.jta.da1.mapper.Tabel1Mapper;import com.kasiait.jta.da1.model.Tabel1;import com.kasiait.jta.da1.service.Tabel1Service;public class Tabel1ServiceImpl implements Tabel1Service {private Tabel1Mapper tabel1Mapper;//spring注入,由于涉及到底层数据源关系,所以我就在配置文件中写的,还希望注解狂public Tabel1Mapper getTabel1Mapper() {return tabel1Mapper;}public void setTabel1Mapper(Tabel1Mapper tabel1Mapper) {this.tabel1Mapper = tabel1Mapper;}@Overridepublic void insertTabel1(Tabel1 t) {// TODO Auto-generated method stubtabel1Mapper.insertTabel1(t);}@Overridepublic List<Tabel1> listPageAll(Tabel1 t) {// TODO Auto-generated method stubreturn tabel1Mapper.listPageAll(t);}} 
/**    * @文件名称: Tabel2ServiceImpl.java * @类路径: com.kasiait.jta.da2.service.impl * @描述: TODO * @作者:kasiait521 * @时间:2014-04-24 */package com.kasiait.jta.da2.service.impl;import com.kasiait.jta.da1.mapper.Tabel1Mapper;import com.kasiait.jta.da1.model.Tabel1;import com.kasiait.jta.da2.mapper.Tabel2Mapper;import com.kasiait.jta.da2.model.Tabel2;import com.kasiait.jta.da2.service.Tabel2Service;public class Tabel2ServiceImpl implements Tabel2Service {    private Tabel2Mapper tabel2Mapper;// 数据源2    private Tabel1Mapper tabel1Mapper;// 数据源1同时注入到这个impl类    public Tabel1Mapper getTabel1Mapper() {        return tabel1Mapper;    }    public void setTabel1Mapper(Tabel1Mapper tabel1Mapper) {        this.tabel1Mapper = tabel1Mapper;    }    public Tabel2Mapper getTabel21Mapper() {        return tabel2Mapper;    }    public void setTabel2Mapper(Tabel2Mapper tabel2Mapper) {        this.tabel2Mapper = tabel2Mapper;    }    @Override    public void insertTabel2(Tabel2 t) {// 在这里进行处理的都会在一个事物里        // TODO Auto-generated method stub        Tabel2 t2 = new Tabel2();        t2.setId(10);        Tabel1 t1 = new Tabel1();        t1.setId(10);        tabel2Mapper.insertTabel2(t2);// 向数据库da2里插入数据        tabel1Mapper.insertTabel1(t1);// 向数据库da1里插入数据    }}
controller类

@Controller@RequestMapping("/kaisiat")public class FrontIndexController {@Autowiredprivate Tabel1Service tabel1Service;@Autowiredprivate Tabel2Service tabel2Service;/** *  * @描述: 网站入口 * @作者: kasiait521 * @日期:2014-04-24 * @修改内容 * @参数: @return * @return String * @throws */@RequestMapping(value = "index", method = RequestMethod.GET)public ModelAndView index(HttpServletRequest request,HttpServletResponse response, HttpSession session) {// 在这里我只是模拟了操作,但并未转到具体的页面中,只是一个测试而已;// 如果系统配置好了,第一次执行时没有问题的,第二次的时候,你可以把tabel2Service中的实现类的da2改一下插入的数据;// 因为数据库中默认的都是主键所以都是唯一值,这样如果没有事物的话,da1是插入失败,da2是插入成功的;// 所以正好测试一下,结果肯定是da1和da2都插入失败了,因为事物回滚了。ModelAndView mv = new ModelAndView();Tabel2 t2 = new Tabel2();tabel2Service.insertTabel2(t2);return mv;}}


3.配置文件

mybatis/da1中的sqlmap-config.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD SQL Map Config 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><typeAliases><typeAlias type="com.kasiait.jta.da1.model.Tabel1"alias="Tabel1" /></typeAliases>        <--系统分页,可忽略-->        <plugins><plugin interceptor="com.kasiait.framework.plugin.PagePlugin"><property name="dialect" value="mysql" /><property name="pageSqlId" value=".*listPage.*" /></plugin></plugins><mappers><mapper resource="mybatis/da1/Tabel1.xml" /></mappers></configuration>

mybatis/da1中的Tabel1.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.kasiait.jta.da1.mapper.Tabel1Mapper"><!-- 从数据库到java实体对象映射声明 --><resultMap type="Tabel1" id="Tabel1ResultMap"><result column="id" property="id" /></resultMap><insert id="insertTabel1" parameterType="Tabel1">insert into table1 (id)values (#{id})</insert><select id="listPageAll" resultMap="Tabel1ResultMap">select * from table1</select></mapper>

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"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"default-lazy-init="true"><import resource="ApplicationContext-service.xml" /><!-- spring atomikos --><!-- mysql da1数据源 这里没有从配置文件中获取,大家可以修改一下呢 --><bean id="mysqlDA1" class="com.atomikos.jdbc.AtomikosDataSourceBean"init-method="init" destroy-method="close"><description>mysql first datasource</description><property name="uniqueResourceName"><value>mysql_da1</value></property><property name="xaDataSourceClassName"><value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value></property><property name="xaProperties"><props><prop key="user">root</prop><prop key="password">root</prop><prop key="url">jdbc:mysql://127.0.0.1:3306/da1</prop></props></property><property name="poolSize" value="10" /></bean><!-- mysql da2数据源 --><bean id="mysqlDA2" class="com.atomikos.jdbc.AtomikosDataSourceBean"init-method="init" destroy-method="close"><description>mysql second datasource</description><property name="uniqueResourceName"><value>mysql_da2</value></property><property name="xaDataSourceClassName"><value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value></property><property name="xaProperties"><props><prop key="user">root</prop><prop key="password">root</prop><prop key="url">jdbc:mysql://127.0.0.1:3306/da2</prop></props></property><property name="poolSize" value="10" /></bean><!-- atomikos事务经管器 --><bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"init-method="init" destroy-method="close"><description>UserTransactionManager</description><property name="forceShutdown"><value>true</value></property></bean><bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"><property name="transactionTimeout" value="300" /></bean><!-- spring 事务经管器 --><bean id="springTransactionManager"class="org.springframework.transaction.jta.JtaTransactionManager"><property name="transactionManager"><ref bean="atomikosTransactionManager" /></property><property name="userTransaction"><ref bean="atomikosUserTransaction" /></property></bean><!-- 通知配置 --><tx:advice id="txAdvice" transaction-manager="springTransactionManager"><tx:attributes><tx:method name="delete*" rollback-for="Exception" /><tx:method name="save*" rollback-for="Exception" /><tx:method name="update*" rollback-for="Exception" /><tx:method name="*" read-only="true" rollback-for="Exception" /></tx:attributes></tx:advice><!-- 事务切面配置 --><aop:config><aop:pointcut id="serviceOperation" expression="execution(* *..service*..*(..))" /><aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" /></aop:config><!-- 第一个数据源 --><bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="mysqlDA1" /><property name="configLocation" value="classpath:mybatis/da1/sqlmap-config.xml" /></bean><!-- 第二个数据源 --><bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="mysqlDA2" /><property name="configLocation" value="classpath:mybatis/da2/sqlmap-config.xml" /></bean></beans>
ApplicationContext-mvc.xml

<?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:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><!--mvc:annotation-driven/ --><context:component-scanbase-package="com.kasiait.jta, com.kasiait.jta.da1, com.kasiait.jta.da2" /><!-- 使用方法级拦截器 --><bean id="methodInvokerIntercepterManager"class="org.springframework.web.servlet.mvc.annotation.MethodInvokerIntercepterManager"><property name="intercepters"><list><bean class="com.kasiait.framework.interceptor.PrivilegeIntercepter" /></list></property></bean><bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"><property name="methodInvokerIntercepterManager" ref="methodInvokerIntercepterManager" /></bean><!-- springmvc视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/" /><property name="suffix" value=".jsp" /></bean><!-- 处理JSON数据转换的 --><bean id="mappingJacksonHttpMessageConverter"class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"><!-- 为了处理返回的JSON数据的编码,默认是ISO-88859-1的,这里把它设置为UTF-8,解决有乱码的情况 --><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value></list></property></bean></beans>

ApplicationContext-service.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 因为没有用注解,所以只好在这里配置了,我觉得这样以后维护起来比较方便呢 --><bean id="tabel1Mapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="sqlSessionFactory" ref="sqlSessionFactory1" /><property name="mapperInterface" value="com.kasiait.jta.da1.mapper.Tabel1Mapper" /></bean><bean id="tabel2Mapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="sqlSessionFactory" ref="sqlSessionFactory2" /><property name="mapperInterface" value="com.kasiait.jta.da2.mapper.Tabel2Mapper" /></bean><bean id="tabel1Service" class="com.kasiait.jta.da1.service.impl.Tabel1ServiceImpl"><property name="tabel1Mapper" ref="tabel1Mapper" /></bean><bean id="tabel2Service" class="com.kasiait.jta.da2.service.impl.Tabel2ServiceImpl"><property name="tabel2Mapper" ref="tabel2Mapper" /><property name="tabel1Mapper" ref="tabel1Mapper" /></bean></beans>

jta.properties jta的配置文件

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactorycom.atomikos.icatch.console_file_name=tm.outcom.atomikos.icatch.log_base_name=tmlogcom.atomikos.icatch.tm_unique_name=tmcom.atomikos.icatch.console_log_level=INFO

到这里就基本结束了,刚开始写博客,没想到写了好几个小时,不过还是蛮幸福的,大家一起分享,一起进步!

下面是这个项目中atomikos的jar包,其他的spring3.2+mybatis3的包,网上有很多呢,我就不上传了

http://download.csdn.net/detail/kasiait521/7249723





0 0