背景:

  1、系统采用SSM架构、需要在10多个MYSQL数据库之间进行切换并对数据进行操作,上篇博文《springMVC+Mybatis(使用AbstractRoutingDataSource实现多数据源切换时)事务管理未生效的解决办法》

  2、第一步先通过AbstractRoutingDataSource实现了多数据源的灵活切换,但是后来发现事务不起作用;

  3、发现问题是因为重复扫描service包导致第二次扫入容器的BEAN没有纳入事务管理,因此在springMVC的配置文件中排除了对Service注解的扫描,防止重复扫描,事务生效了,测试又发现数据源不能成功切换了;

  4、查阅资料发现是由于spring默认提供的事务管理DataSourceTransactionManager只能管理一个数据源的事务,因此考虑使用atomikos+JTA进行分布式事务管理

配置文件:

  1、jdbc.properties

  配置你需要连接的数据库资源

jdbc_zhs.driverClassName=com.mysql.jdbc.Driver
jdbc_zhs.url.spider=jdbc:mysql://127.0.0.1:3306/fms?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_zhs.username=root
jdbc_zhs.password=root jdbc_jcs.driverClassName=com.mysql.jdbc.Driver
jdbc_jcs.url.spider=jdbc:mysql://127.0.0.1:3306/fms-jcs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_jcs.username=root
jdbc_jcs.password=root jdbc_hks.driverClassName=com.mysql.jdbc.Driver
jdbc_hks.url.spider=jdbc:mysql://127.0.0.1:3306/fms-hks?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_hks.username=root
jdbc_hks.password=root jdbc_xts.driverClassName=com.mysql.jdbc.Driver
jdbc_xts.url.spider=jdbc:mysql://127.0.0.1:3306/fms-xts?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_xts.username=root
jdbc_xts.password=root jdbc_xxgcs.driverClassName=com.mysql.jdbc.Driver
jdbc_xxgcs.url.spider=jdbc:mysql://127.0.0.1:3306/fms-xxgcs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_xxgcs.username=root
jdbc_xxgcs.password=root jdbc_zdhs.driverClassName=com.mysql.jdbc.Driver
jdbc_zdhs.url.spider=jdbc:mysql://127.0.0.1:3306/fms-zdhs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_zdhs.username=root
jdbc_zdhs.password=root jdbc_gfs.driverClassName=com.mysql.jdbc.Driver
jdbc_gfs.url.spider=jdbc:mysql://127.0.0.1:3306/fms-gfs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_gfs.username=root
jdbc_gfs.password=root jdbc_kxs.driverClassName=com.mysql.jdbc.Driver
jdbc_kxs.url.spider=jdbc:mysql://127.0.0.1:3306/fms-kxs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_kxs.username=root
jdbc_kxs.password=root jdbc_fyd.driverClassName=com.mysql.jdbc.Driver
jdbc_fyd.url.spider=jdbc:mysql://127.0.0.1:3306/fms-fyd?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_fyd.username=root
jdbc_fyd.password=root jdbc_ybj.driverClassName=com.mysql.jdbc.Driver
jdbc_ybj.url.spider=jdbc:mysql://127.0.0.1:3306/fms-ybj?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_ybj.username=root
jdbc_ybj.password=root jdbc_yzh.driverClassName=com.mysql.jdbc.Driver
jdbc_yzh.url.spider=jdbc:mysql://127.0.0.1:3306/fms-yzh?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc_yzh.username=root
jdbc_yzh.password=root

  2、applicationContext-common.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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 启动扫描 -->
<context:component-scan base-package="com.fms;com.job;com.jmda;">
<!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> -->
</context:component-scan> <!-- 文件上传 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10240000"/>
<property name="maxInMemorySize" value="10240000" />
</bean> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPaths">
<list>
<value>/WEB-INF/pages/</value>
<value>/WEB-INF/template/</value>
<value>classpath:/jmda-ftl/</value>
</list>
</property>
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">0</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="number_format">0.##########</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="classic_compatible">true</prop>
<prop key="template_exception_handler">ignore</prop>
</props>
</property>
</bean> <!-- 启用CGliB -->
<aop:aspectj-autoproxy /> <!-- 配置c3p0数据源,项目中有代码需要C3P0数据源支持时额外配置,不需要可以不配置 -->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="jdbcUrl">
<value><![CDATA[jdbc:mysql://localhost:3306/fms-zhs?useUnicode=yes&characterEncoding=UTF8]]></value>
</property>
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="maxPoolSize" value="200" />
<property name="minPoolSize" value="1" />
<property name="initialPoolSize" value="1" />
<property name="maxIdleTime" value="30" />
<property name="acquireIncrement" value="5" />
<property name="maxStatements" value="0" />
<property name="idleConnectionTestPeriod" value="60" />
<property name="acquireRetryAttempts" value="30" />
<property name="breakAfterAcquireFailure" value="true" />
<property name="testConnectionOnCheckout" value="false" />
</bean> <!-- 注入数据源连接配置文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:/spring/jdbc.properties</value>
</list>
</property>
</bean> <!-- 多个数据源的公用配置,方便下面直接引用 -->
<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close" abstract="true">
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="poolSize" value="10" />
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="30"/>
<property name="borrowConnectionTimeout" value="60"/>
<property name="reapTimeout" value="20"/>
<!-- 最大空闲时间 -->
<property name="maxIdleTime" value="60"/>
<property name="maintenanceInterval" value="60" />
<property name="loginTimeout" value="60"/>
<property name="logWriter" value="60"/>
<property name="testQuery">
<value>select 1</value>
</property> </bean> <!-- 下面是所有需要切换的数据源 -->
<!-- 综合所数据源 -->
<bean id="ds_zhs" parent="abstractXADataSource">
<!-- value只要多个XA数据源之间不重复就行,随便取名 -->
<property name="uniqueResourceName" value="mysql/zhs" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_zhs.url.spider}</prop>
<prop key="user">${jdbc_zhs.username}</prop>
<prop key="password">${jdbc_zhs.password}</prop>
</props>
</property>
</bean> <!-- 舰船所数据源-->
<bean id="ds_jcs" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/jcs" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_jcs.url.spider}</prop>
<prop key="user">${jdbc_jcs.username}</prop>
<prop key="password">${jdbc_jcs.password}</prop>
</props>
</property>
</bean> <!-- 航空所数据源-->
<bean id="ds_hks" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/hks" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_hks.url.spider}</prop>
<prop key="user">${jdbc_hks.username}</prop>
<prop key="password">${jdbc_hks.password}</prop>
</props>
</property>
</bean> <!-- 系统所数据源-->
<bean id="ds_xts" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/xts" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_xts.url.spider}</prop>
<prop key="user">${jdbc_xts.username}</prop>
<prop key="password">${jdbc_xts.password}</prop>
</props>
</property>
</bean> <!-- 信息工程所数据源-->
<bean id="ds_xxgcs" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/xxgcs" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_xxgcs.url.spider}</prop>
<prop key="user">${jdbc_xxgcs.username}</prop>
<prop key="password">${jdbc_xxgcs.password}</prop>
</props>
</property>
</bean> <!-- 自动化所数据源-->
<bean id="ds_zdhs" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/zdhs" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_zdhs.url.spider}</prop>
<prop key="user">${jdbc_zdhs.username}</prop>
<prop key="password">${jdbc_zdhs.password}</prop>
</props>
</property>
</bean> <!-- 规范所数据源-->
<bean id="ds_gfs" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/gfs" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_gfs.url.spider}</prop>
<prop key="user">${jdbc_gfs.username}</prop>
<prop key="password">${jdbc_gfs.password}</prop>
</props>
</property>
</bean> <!-- 科信所数据源-->
<bean id="ds_kxs" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/kxs" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_kxs.url.spider}</prop>
<prop key="user">${jdbc_kxs.username}</prop>
<prop key="password">${jdbc_kxs.password}</prop>
</props>
</property>
</bean> <!-- 翻译队数据源-->
<bean id="ds_fyd" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/fyd" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_fyd.url.spider}</prop>
<prop key="user">${jdbc_fyd.username}</prop>
<prop key="password">${jdbc_fyd.password}</prop>
</props>
</property>
</bean> <!-- 院本级数据源-->
<bean id="ds_ybj" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/ybj" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_ybj.url.spider}</prop>
<prop key="user">${jdbc_ybj.username}</prop>
<prop key="password">${jdbc_ybj.password}</prop>
</props>
</property>
</bean> <!-- 院综合系统数据源-->
<bean id="ds_yzh" parent="abstractXADataSource">
<property name="uniqueResourceName" value="mysql/yzh" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${jdbc_yzh.url.spider}</prop>
<prop key="user">${jdbc_yzh.username}</prop>
<prop key="password">${jdbc_yzh.password}</prop>
</props>
</property>
</bean> <!-- 配置多数据源 MultipleDataSource-->
<bean name="dynamicDatasource" class="com.fms.common.datasource.MultipleDataSource">
<property name="targetDataSources">
<map>
<!-- key和value-ref尽量保持一致,我在测试的时候因为名称不一致一致报错,
找了好久都没找到原因,最后统一了名称终于成功启动了 -->
<entry key="ds_zhs" value-ref="ds_zhs"/>
<entry key="ds_jcs" value-ref="ds_jcs"/>
<entry key="ds_hks" value-ref="ds_hks"/>
<entry key="ds_xts" value-ref="ds_xts"/>
<entry key="ds_xxgcs" value-ref="ds_xxgcs"/>
<entry key="ds_zdhs" value-ref="ds_zdhs"/>
<entry key="ds_gfs" value-ref="ds_gfs"/>
<entry key="ds_kxs" value-ref="ds_kxs"/>
<entry key="ds_fyd" value-ref="ds_fyd"/>
<entry key="ds_ybj" value-ref="ds_ybj"/>
<entry key="ds_yzh" value-ref="ds_yzh"/>
</map>
</property>
<!-- 指定一个默认的数据源,即在不需要切换数据源时,本地系统默认使用的数据源 -->
<property name="defaultTargetDataSource" ref="ds_zhs" />
</bean> <!-- 下面开始配置SqlSessionFactoryBean,有多少个数据源需要支持就陪多少个 -->
<bean id="sqlSessionFactory_zhs" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- dataSource的ref对应数据源的id -->
<property name="dataSource" ref="ds_zhs"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_jcs" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_jcs"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_hks" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_hks"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_xts" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_xts"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_xxgcs" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_xxgcs"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_zdhs" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_zdhs"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_gfs" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_gfs"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_kxs" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_kxs"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_fyd" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_fyd"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_ybj" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_ybj"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactory_yzh" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds_yzh"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:/com/fms/**/dao/*Mapper.xml</value>
<value>classpath*:/com/fms/**/dao/*DAO.xml</value>
</list>
</property>
</bean> <!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 -->
<bean id="sqlSessionTemplate" class="com.fms.common.datasource.CustomSqlSessionTemplate" scope="prototype">
<!-- 构造注入参数指定本地默认数据源对应的SqlSessionFactoryBean -->
<constructor-arg ref="sqlSessionFactory_zhs" />
<property name="targetSqlSessionFactorys">
<map>
<!-- key和上文配置的数据源的id值尽量保持一致,我在测试的时候因为名称不一致一致报错,
找了好久都没找到原因,最后统一了名称终于成功启动了 -->
<entry value-ref="sqlSessionFactory_zhs" key="ds_zhs"/>
<entry value-ref="sqlSessionFactory_jcs" key="ds_jcs"/>
<entry value-ref="sqlSessionFactory_hks" key="ds_hks"/>
<entry value-ref="sqlSessionFactory_xts" key="ds_xts"/>
<entry value-ref="sqlSessionFactory_xxgcs" key="ds_xxgcs"/>
<entry value-ref="sqlSessionFactory_zdhs" key="ds_zdhs"/>
<entry value-ref="sqlSessionFactory_gfs" key="ds_gfs"/>
<entry value-ref="sqlSessionFactory_kxs" key="ds_kxs"/>
<entry value-ref="sqlSessionFactory_fyd" key="ds_fyd"/>
<entry value-ref="sqlSessionFactory_ybj" key="ds_ybj"/>
<entry value-ref="sqlSessionFactory_yzh" key="ds_yzh"/>
</map>
</property>
</bean> <!-- 配置mybatis接口扫描 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.fms.**.dao" />
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
</bean> <!-- jta配置,直接复用,不需要修改 -->
<!-- jta配置开始 -->
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown">
<value>true</value>
</property>
</bean> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean> <bean id="springTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref bean="atomikosTransactionManager" />
</property>
<property name="userTransaction">
<ref bean="atomikosUserTransaction" />
</property>
</bean>
<!-- jta配置结束 --> <!-- 配置事务管理 -->
<tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" /> </beans>

  3、springmvc-servlet.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:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"> <context:component-scan base-package="com.fms;com.jmda;com.job;" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<!-- <context:annotation-config/> --> <!-- message-converters -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven> <!-- 视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8"></property>
<property name="requestContextAttribute" value="request" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
</bean> <!-- 静态资源 -->
<mvc:resources mapping="/static/**" location="/static/" />
<mvc:resources mapping="/jmda-static/**" location="/jmda-static/" />
<mvc:resources mapping="/assets/**" location="/assets/" /> <!-- 拦截器 -->
<mvc:interceptors>
<bean class="com.fms.common.listener.SecurityInterceptor"/>
</mvc:interceptors>
</beans>

  4、web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/spring/applicationContext*.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <servlet>
<servlet-name>spring4mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring4mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--文件下载 -->
<servlet>
<servlet-name>ServletDownload</servlet-name>
<servlet-class>com.fms.business.sjtb.service.ServletDownload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDownload</servlet-name>
<url-pattern>/servlet/download</url-pattern>
</servlet-mapping>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>com.fms.common.listener.CommListener</listener-class>
</listener>
<!-- 400错误 -->
<error-page>
<error-code>400</error-code>
<location>/error</location>
</error-page>
<!-- 404 页面不存在错误 -->
<error-page>
<error-code>404</error-code>
<location>/error</location>
</error-page>
<!-- 403 服务器拒绝请求 -->
<error-page>
<error-code>403</error-code>
<location>/error</location>
</error-page>
<!-- 500 服务器内部错误 -->
<error-page>
<error-code>500</error-code>
<location>/error</location>
</error-page>
<!-- 503 服务不可用 -->
<error-page>
<error-code>503</error-code>
<location>/error</location>
</error-page>
<!-- java.lang.Exception -->
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error</location>
</error-page>
<!-- java.lang.NullPointerException -->
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/error</location>
</error-page>
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/error</location>
</error-page>
<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>
</web-app>

  5、在resources文件夹下增加jta.properties文件:

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name = tm.out
com.atomikos.icatch.log_base_name = tmlog
com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
com.atomikos.icatch.console_log_level=WARN

 

JAVA代码:

  1.MultipleDataSource:

package com.fms.common.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class MultipleDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();

    //将数据源重置为默认数据源
public static void changeTodefaultDataSource() {
dataSourceKey.remove();
}
// //院
// public static void setDataSourceY(){
// dataSourceKey.remove();
// dataSourceKey.set("yzhDataSource");
// } //将数据源设置为配置文件中key值为dataSource参数对应的值的数据源
public static void setDataSource(String dataSource){
dataSourceKey.remove();
dataSourceKey.set(dataSource);
} //获取当前数据源的key值
public static String getKey(){
return dataSourceKey.get();
} //重写AbstractRoutingDataSource的方法,提供当前的数据源用于连接
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get();
} }

  2、自定义的SqlSessionTemlate类:

  CustomSqlSessionTemplate

package com.fms.common.datasource;

import static java.lang.reflect.Proxy.newProxyInstance;
import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;
import static org.mybatis.spring.SqlSessionUtils.closeSqlSession;
import static org.mybatis.spring.SqlSessionUtils.getSqlSession;
import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.List;
import java.util.Map; import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.Assert; public class CustomSqlSessionTemplate extends SqlSessionTemplate { private final SqlSessionFactory sqlSessionFactory;
private final ExecutorType executorType;
private final SqlSession sqlSessionProxy;
private final PersistenceExceptionTranslator exceptionTranslator; private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
private SqlSessionFactory defaultTargetSqlSessionFactory; public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {
this.targetSqlSessionFactorys = targetSqlSessionFactorys;
} public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {
this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
} public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
} public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration()
.getEnvironment().getDataSource(), true));
} public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) { super(sqlSessionFactory, executorType, exceptionTranslator); this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor()); this.defaultTargetSqlSessionFactory = sqlSessionFactory;
} @Override
public SqlSessionFactory getSqlSessionFactory() { SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(MultipleDataSource.getKey());
if (targetSqlSessionFactory != null) {
return targetSqlSessionFactory;
} else if (defaultTargetSqlSessionFactory != null) {
return defaultTargetSqlSessionFactory;
} else {
Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
}
return this.sqlSessionFactory;
} @Override
public Configuration getConfiguration() {
return this.getSqlSessionFactory().getConfiguration();
} public ExecutorType getExecutorType() {
return this.executorType;
} public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
return this.exceptionTranslator;
} /**
* {@inheritDoc}
*/
public <T> T selectOne(String statement) {
return this.sqlSessionProxy.<T> selectOne(statement);
} /**
* {@inheritDoc}
*/
public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.<T> selectOne(statement, parameter);
} /**
* {@inheritDoc}
*/
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey);
} /**
* {@inheritDoc}
*/
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey);
} /**
* {@inheritDoc}
*/
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds);
} /**
* {@inheritDoc}
*/
public <E> List<E> selectList(String statement) {
return this.sqlSessionProxy.<E> selectList(statement);
} /**
* {@inheritDoc}
*/
public <E> List<E> selectList(String statement, Object parameter) {
return this.sqlSessionProxy.<E> selectList(statement, parameter);
} /**
* {@inheritDoc}
*/
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds);
} /**
* {@inheritDoc}
*/
public void select(String statement, ResultHandler handler) {
this.sqlSessionProxy.select(statement, handler);
} /**
* {@inheritDoc}
*/
public void select(String statement, Object parameter, ResultHandler handler) {
this.sqlSessionProxy.select(statement, parameter, handler);
} /**
* {@inheritDoc}
*/
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
this.sqlSessionProxy.select(statement, parameter, rowBounds, handler);
} /**
* {@inheritDoc}
*/
public int insert(String statement) {
return this.sqlSessionProxy.insert(statement);
} /**
* {@inheritDoc}
*/
public int insert(String statement, Object parameter) {
return this.sqlSessionProxy.insert(statement, parameter);
} /**
* {@inheritDoc}
*/
public int update(String statement) {
return this.sqlSessionProxy.update(statement);
} /**
* {@inheritDoc}
*/
public int update(String statement, Object parameter) {
return this.sqlSessionProxy.update(statement, parameter);
} /**
* {@inheritDoc}
*/
public int delete(String statement) {
return this.sqlSessionProxy.delete(statement);
} /**
* {@inheritDoc}
*/
public int delete(String statement, Object parameter) {
return this.sqlSessionProxy.delete(statement, parameter);
} /**
* {@inheritDoc}
*/
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
} /**
* {@inheritDoc}
*/
public void commit() {
throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
} /**
* {@inheritDoc}
*/
public void commit(boolean force) {
throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession");
} /**
* {@inheritDoc}
*/
public void rollback() {
throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
} /**
* {@inheritDoc}
*/
public void rollback(boolean force) {
throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession");
} /**
* {@inheritDoc}
*/
public void close() {
throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession");
} /**
* {@inheritDoc}
*/
public void clearCache() {
this.sqlSessionProxy.clearCache();
} /**
* {@inheritDoc}
*/
public Connection getConnection() {
return this.sqlSessionProxy.getConnection();
} /**
* {@inheritDoc}
* @since 1.0.2
*/
public List<BatchResult> flushStatements() {
return this.sqlSessionProxy.flushStatements();
} /**
* Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also
* unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to
* the {@code PersistenceExceptionTranslator}.
*/
private class SqlSessionInterceptor implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final SqlSession sqlSession = getSqlSession(
CustomSqlSessionTemplate.this.getSqlSessionFactory(),
CustomSqlSessionTemplate.this.executorType,
CustomSqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory())) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator
.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory());
}
}
} }

  3、数据源切换切面ChooseDataSourceAspect:

package com.fms.common.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; import com.fms.common.annotation.ChooseDataSource;
import com.fms.common.datasource.MultipleDataSource;
import com.fms.common.utils.reflect.ReflectUtil; /**
* 类描述:完成数据源的切换,抽类切面,具体项目继承一下,不需要重写即可使用
*/
@Aspect
public abstract class ChooseDataSourceAspect { protected static final ThreadLocal<String> preDatasourceHolder = new ThreadLocal<String>(); @Pointcut("@annotation(com.fms.common.annotation.ChooseDataSource)")
public void methodWithChooseAnnotation() {
System.err.println("************************************************//////////////////////////////////////////");
} /**
* 根据@ChooseDataSource的属性值设置不同的dataSourceKey,以供DynamicDataSource
*/
@Before("methodWithChooseAnnotation()")
public void changeDataSourceBeforeMethodExecution(JoinPoint jp) {
//拿到anotation中配置的数据源
String resultDS = determineDatasource(jp);
//没有配置实用默认数据源
if (resultDS == null) {
MultipleDataSource.changeTodefaultDataSource();
return;
}
preDatasourceHolder.set(MultipleDataSource.getKey());
//将数据源设置到数据源持有者
MultipleDataSource.setDataSource(resultDS); } /**
* 如果需要修改获取数据源的逻辑,请重写此方法 *
* @param jp
* @return
*/
@SuppressWarnings("rawtypes")
protected String determineDatasource(JoinPoint jp) {
String methodName = jp.getSignature().getName();
Class targetClass = jp.getSignature().getDeclaringType();
String dataSourceForTargetClass = resolveDataSourceFromClass(targetClass);
String dataSourceForTargetMethod = resolveDataSourceFromMethod(targetClass, methodName);
String resultDS = determinateDataSource(dataSourceForTargetClass, dataSourceForTargetMethod);
return resultDS;
} /**
* 方法执行完毕以后,数据源切换回之前的数据源。
* 比如foo()方法里面调用bar(),但是bar()另外一个数据源,
* bar()执行时,切换到自己数据源,执行完以后,要切换到foo()所需要的数据源,以供
* foo()继续执行。
*/
@After("methodWithChooseAnnotation()")
public void restoreDataSourceAfterMethodExecution() {
MultipleDataSource.setDataSource(preDatasourceHolder.get());
preDatasourceHolder.remove();
} /**
* @param targetClass
* @param methodName
* @return
*/
@SuppressWarnings("rawtypes")
private String resolveDataSourceFromMethod(Class targetClass, String methodName) { Method m = ReflectUtil.findUniqueMethod(targetClass, methodName);
if (m != null) {
ChooseDataSource choDs = m.getAnnotation(ChooseDataSource.class);
return resolveDataSourcename(choDs);
}
return null;
} /**
* 方法描述 :
* 确定最终数据源,如果方法上设置有数据源,则以方法上的为准,如果方法上没有设置,则以类上的为准,如果类上没有设置,则使用默认数据源
*
* @param classDS
* @param methodDS
* @return
*/
private String determinateDataSource(String classDS, String methodDS) {
// if (null == classDS && null == methodDS) {
// return null;
// }
// 两者必有一个不为null,如果两者都为Null,也会返回Null
return methodDS == null ? classDS : methodDS;
} /**
* 方法描述 : 类级别的 @ChooseDataSource的解析
*
* @param targetClass
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private String resolveDataSourceFromClass(Class targetClass) {
ChooseDataSource classAnnotation = (ChooseDataSource) targetClass
.getAnnotation(ChooseDataSource.class);
// 直接为整个类进行设置
return null != classAnnotation ? resolveDataSourcename(classAnnotation)
: null;
} /**
* 方法描述 :
* 组装DataSource的名字
*
* @param ds
* @return
*/
private String resolveDataSourcename(ChooseDataSource ds) {
return ds == null ? null : ds.value();
} }

  4、数据源切换注解ChooseDataSource:

package com.fms.common.annotation;

import java.lang.annotation.*;

/**
* 注解式数据源,用来进行数据源切换
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChooseDataSource { String value() default "";
}

  5、使用方式:

  TestService:

package com.fms.business;

import java.util.Map;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.fms.common.dao.table.mapper.WfWorkflowPOMapper;
import com.fms.common.datasource.MultipleDataSource;
import com.fms.common.model.po.WfWorkflowPO;
import com.google.common.collect.Maps; @Service(value="testService")
public class TestService { //注入SqlSessionTemplate,执行自定义的Mapper.xml文件
@Autowired
SqlSessionTemplate sqlSessionTemplate;
String nameSpace = "com.fms.business.dao.TestServiceMapper"; @Transactional
public void test() throws Exception{
Map<String, Object> param = Maps.newHashMap();
param.put("id", "123");
param.put("name", "zhangsan");
//默认数据源ds_zhs
sqlSessionTemplate.insert(nameSpace+".testInsert", param);
//切换至ds_jcs
MultipleDataSource.setDataSource("ds_jcs");
sqlSessionTemplate.insert(nameSpace+".testInsert", param);
} @Transactional
public void test1() throws Exception{
Map<String, Object> param = Maps.newHashMap();
param.put("id", "124");
param.put("name", "lisi");
//默认数据源ds_zhs
sqlSessionTemplate.insert(nameSpace+".testInsert", param);
//切换至ds_jcs
MultipleDataSource.setDataSource("ds_jcs");
sqlSessionTemplate.insert(nameSpace+".testInsert", param);
//编写抛出异常的代码测试事务回滚
String str = null;
str.trim();
} //使用MyBatis自动生成的Mapper接口
@Autowired
WfWorkflowPOMapper wfWorkflowPOMapper;
@Transactional
public void test2() throws Exception{
WfWorkflowPO record = new WfWorkflowPO();
record.setWorkflowId("12345");
record.setName("xxxx");
wfWorkflowPOMapper.insert(record);
//切换至ds_jcs
MultipleDataSource.setDataSource("ds_jcs");
wfWorkflowPOMapper.insert(record);
//切换至ds_yzh
MultipleDataSource.setDataSource("ds_yzh");
wfWorkflowPOMapper.insert(record);
} }

  TestController:

package com.fms.business;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
public class TestController { @Autowired
TestService testService; @RequestMapping("/test")
@ResponseBody
public String test(){
try {
testService.test();
return "ok";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
} @RequestMapping("/test1")
@ResponseBody
public String test1(){
try {
testService.test1();
return "ok";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
} @RequestMapping("/test2")
@ResponseBody
public String test2(){
try {
testService.test2();
return "ok";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
}Aspect

  原例中还有使用@ChooseDataSource注解切换数据源的用法,需要AspectJ编译,捣鼓了一下没成功,数据源能够切换,但是分布式事务不起作用,有兴趣可以自己试试自己调试修改。

  在项目中加入一个继承ChooseDataSourceAspect的类即可:

package com.fms.business;ChooseDataSource

import org.aspectj.lang.annotation.Aspect;

import com.fms.common.aop.ChooseDataSourceAspect;

@Component
@Aspect
public class TestAspect extends ChooseDataSourceAspect { }

  参考博文:http://www.blogjava.net/zuxiong/archive/2015/09/24/427471.html

spring+springMVC+Mybatis架构下采用AbstractRoutingDataSource、atomikos、JTA实现多数据源灵活切换以及分布式事务管理的更多相关文章

  1. Spring+SpringMVC+MyBatis深入学习及搭建(十一)——SpringMVC架构

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6985816.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十)--My ...

  2. Spring+SpringMVC+MyBatis+easyUI整合进阶篇(九)Linux下安装redis及redis的常用命令和操作

    redis简介 Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis与其他key-value缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存 ...

  3. Java架构学习 转(Spring+SpringMVC+MyBatis+easyUI)

    Spring+SpringMVC+MyBatis+easyUI : http://www.cnblogs.com/han-1034683568/p/6730869.html

  4. 基于Spring+SpringMVC+Mybatis的Web系统搭建

    系统搭建的配置大同小异,本文在前人的基础上做了些许的改动,重写数据库,增加依据权限的动态菜单的实现,也增加了后台返回json格式数据的配置,详细参见完整源码. 主要的后端架构:Spring+Sprin ...

  5. Spring+SpringMVC+MyBatis深入学习及搭建(十六)——SpringMVC注解开发(高级篇)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7085268.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十五)——S ...

  6. 用 eclipse 创建一个简单的 meaven spring springMvc mybatis 项目

    下面是整体步骤: 1: 先创建一个Maven 项目: 选择跳过骨架: 因为要搭建的是 web 项目  所以这个地方选择 war 包; 点击完成 这样就完成 Maven项目的搭建: 接下俩 先把 Mav ...

  7. SSM(Spring+SpringMVC+Mybatis)框架环境搭建(整合步骤)(一)

    1. 前言 最近在写毕设过程中,重新梳理了一遍SSM框架,特此记录一下. 附上源码:https://gitee.com/niceyoo/jeenotes-ssm 2. 概述 在写代码之前我们先了解一下 ...

  8. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

  9. java实现微信支付宝等多个支付平台合一的二维码支付(maven+spring springmvc mybatis框架)

    首先申明,本人实现微信支付宝等支付平台合多为一的二维码支付,并且实现有效时间内支付有效,本人采用的框架是spring springmvc mybatis 框架,maven管理.其实如果支付,不需要my ...

随机推荐

  1. UVA11722 Jonining with Friend

    Joining with Friend You are going from Dhaka to Chittagong by train and you came to know one of your ...

  2. 如何将本地项目上传到Git 版本库

    1.(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库 git init 2.把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点 ...

  3. MAC中怎么安装python

    转自:https://blog.csdn.net/hou_manager/article/details/79555809 一.Python 介绍 Python介绍 Python3在2008年12月3 ...

  4. 20190922-雅礼Day2

    先送大家几个变量名: 具体的可以去$C++ \ Reference$里看(本页 右侧/下侧 有链接) 或者等一下奇迹银桥第三氮 const int c; mutable int a; volatile ...

  5. Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---命令模式之RemoteControlTest[转]

      1   2{<HeadFirst设计模式>之命令模式 }   3{ 本单元中的类为命令的接收者      }   4{ 编译工具 :Delphi7.0         }   5{ 联 ...

  6. LintCode 两两交换链表中的节点

    给一个链表,两两交换其中的节点,然后返回交换后的链表. 样例 给出 1->2->3->4, 你应该返回的链表是 2->1->4->3. 分析:第一次调试的时候用了P ...

  7. linux 调整系统时区

    查看当前时间: date 查看当天详细时区 timedatectl 调整为正确时区 timedatectl set-timezone 'Asia/Shanghai'

  8. FFT初步代码分析和逼近曲线

    FFT:快速傅里叶变换 文章从两个方面来写,一个是FFT的基础知识,也就是将时域信号转换为频域信号,另一个是合成时域信号. 将时域信号转换为频域信号 代码来源于http://bigsec.net/b5 ...

  9. Apache配置虚拟主机,全部指向一个目录

    配置虚拟主机的时候,全部指向了一个目录,解决方法是在httpd.conf中添加: NameVirtualHost *:80

  10. mysql的三种连接方式

    SQL的三种连接方式分为:左外连接.右外连接.内连接,专业术语分别为:LEFT JOIN.RIGHT JOING.INNER JOIN 内连接INNER JOIN:使用比较运算符来根据指定的连接的每个 ...