你的位置:首页 > 软件开发 > Java > spring+springmvc+mybatis+oracle+atomikos+jta实现多数据源事务管理

spring+springmvc+mybatis+oracle+atomikos+jta实现多数据源事务管理

发布时间:2017-11-23 09:00:22
---恢复内容开始--- 在做项目过程中,遇到了需要一个项目中访问两个数据库的情况,发现使用常规的spring管理事务,导致事务不能正常回滚,因此,采用了jta+atomikos的分布式数据源方式对事务进行管理。在此做下记录,以便日后参考,文中 ...

---恢复内容开始---

       在做项目过程中,遇到了需要一个项目中访问两个数据库的情况,发现使用常规的spring管理事务,导致事务不能正常回滚,因此,采用了jta+atomikos的分布式数据源方式对事务进行管理。在此做下记录,以便日后参考,文中用词不当之处,敬请谅解!

配置文件:

1:web.

 

<?   xsi:schemaLocation="http://java.sun.com/ <!-- 加载Spring配置文件 --> <context-param>  <param-name>contextConfigLocation</param-name>  <param-value>classpath:spring/spring.

 

2:pom.

<properties>  <project.build.sourceEncoding>UTF- 8</project.build.sourceEncoding>  <spring.version>4.2.5.RELEASE</spring.version>  <junit.version>4.12</junit.version>  <druid.version>1.0.18</druid.version>  <fastjson.version>1.2.6</fastjson.version>  <mybaitsplus.version>2.0.8</mybaitsplus.version>  <mysql.version>5.1.38</mysql.version>  <log4j.version>1.2.17</log4j.version>  <slf4j.version>1.7.13</slf4j.version>  <aspectjweaver.version>1.8.9</aspectjweaver.version>  <fileupload.version>1.3.1</fileupload.version>  <commons.version>2.4</commons.version>  <jstl.version>1.2</jstl.version> </properties> <dependencies>  <!-- JUnit -->  <dependency>    <groupId>junit</groupId>   <artifactId>junit</artifactId>   <version>${junit.version}</version>   <scope>test</scope>  </dependency>  <!-- spring quartz -->  <dependency>   <groupId>org.quartz-scheduler</groupId>   <artifactId>quartz</artifactId>   <version>2.2.1</version>  </dependency><!-- 添加Hibernate依赖 -->  <dependency>  <groupId>org.hibernate</groupId>  <artifactId>hibernate-core</artifactId>  <version>3.6.10.Final</version>  </dependency>   <!-- redis -->  <dependency>   <groupId>redis.clients</groupId>   <artifactId>jedis</artifactId>   <version>2.5.1</version>  </dependency>  <!-- json -->  <dependency>   <groupId>net.sf.json-lib</groupId>   <artifactId>json-lib</artifactId>   <version>2.4</version>   <classifier>jdk15</classifier>  </dependency>  <dependency>   <groupId>org.codehaus.jackson</groupId>   <artifactId>jackson-core-asl</artifactId>   <version>1.9.11</version>  </dependency>  <dependency>   <groupId>org.codehaus.jackson</groupId>   <artifactId>jackson-mapper-asl</artifactId>   <version>1.9.11</version>  </dependency>  <dependency>   <groupId>com.faster

3:config.properties

 配置数据源属性

 A_jdbc_url=jdbc\:oracle\:thin\:@localhost\:1521\:orcl A_jdbc_username=test_one A_jdbc_password=password B_jdbc_url=jdbc\:oracle\:thin\:@localhost\:1521\:orcl B_jdbc_username=test_two B_jdbc_password=password

4、在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=INFO

5、spring-mvc.

<mvc:default-servlet-handler/> <!-- Controller包(自动注入) --> <context:component-scan base-package="com.zzxw.web.controller"> </context:component-scan> <mvc:annotation-driven>  <!-- 处理responseBody 里面日期类型 -->  <mvc:message-converters>   <bean    class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">    <property name="objectMapper">     <bean class="com.fasterclass="java.text.SimpleDateFormat">        <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />       </bean>      </property>     </bean>    </property>   </bean>   <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" >    <property name="supportedMediaTypes">     <list>      <value>text/html;charset=UTF-8</value>      <value>application/json;charset=UTF-8</value>     </list>    </property>   </bean>  </mvc:message-converters> </mvc:annotation-driven> <!-- 静态资源配置 --> <mvc:resources mapping="/resources/**" location="/resources/"/> <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  <property name="prefix" value="/"/>  <property name="suffix" value=".jsp"/> </bean> <!-- 上传限制 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  <!-- 上传文件大小限制为31M,31*1024*1024 -->  <property name="maxUploadSize" value="32505856"/> </bean>  <bean id="actionLogAdvice" class="com.zzxw.web.annotation.ActionLogAdvice" /> <aop:config>  <aop:pointcut id="actionLog" expression="execution(public * com.zzxw.web.controller..*..*(..)) " />   <aop:advisor pointcut-ref="actionLog" advice-ref="actionLogAdvice"/> </aop:config>  <!-- 总** --> <mvc:interceptors>   <mvc:interceptor>   <mvc:mapping path="/**" />   <mvc:exclude-mapping path="/js/**" />   <mvc:exclude-mapping path="/css/**" />   <mvc:exclude-mapping path="/images/**" />   <bean class="com.zzxw.web.interceptor.SpringRequestInterceptor" />  </mvc:interceptor> </mvc:interceptors>

6:spring-mybatis.

 <!-- 启动AspectJ支持  <aop:aspectj-autoproxy />-->  <context:property-placeholder location="classpath:config.properties" />  <!-- 启用CGliB --><!--  <aop:aspectj-autoproxy /> -->   <!-- 多个数据源的公用配置,方便下面直接引用 -->  <bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"    destroy-method="close" abstract="true">  <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>  <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 * from dual</value>  </property> </bean> 
<!--数据源A--> <bean id="dataSourceA" parent="abstractXADataSource"> <!-- value只要多个XA数据源之间不重复就行,随便取名 --> <property name="uniqueResourceName" value="dataPlat" /> <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource" /> <property name="xaProperties"> <props> <prop key="URL">${A_jdbc_url}</prop> <prop key="user">${A_jdbc_username}</prop> <prop key="password">${A_jdbc_password}</prop> </props> </property> </bean> <!--数据源B--> <bean id="dataSourceB" parent="abstractXADataSource"> <property name="uniqueResourceName" value="risk" /> <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource" /> <property name="xaProperties"> <props> <prop key="URL">${B_jdbc_url}</prop> <prop key="user">${B_jdbc_username}</prop> <prop key="password">${B_jdbc_password}</prop> </props> </property> </bean> <!-- Spring整合Mybatis,更多查看文档:http://mp.baomidou.com --> <bean id="sqlSessionFactory_A" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSourceA"/> <!-- 自动扫描Mapping.class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"> <property name="dialectType" value="oracle"/> </bean> </array> </property> <!-- 全局配置注入 --> <property name="globalConfig" ref="globalConfig" /> </bean> <!-- Spring整合Mybatis,更多查看文档:http://mp.baomidou.com --> <bean id="sqlSessionFactory_B" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSourceB"/> <!-- 自动扫描Mapping. <!--对应的实体类--> <property name="typeAliasesPackage" value="com.zzxw.web.domain"/> <property name="plugins"> <array> <!-- 分页插件配置 --> <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"> <property name="dialectType" value="oracle"/> </bean> </array> </property> <!-- 全局配置注入 --> <property name="globalConfig" ref="globalConfig" /> </bean> <!-- 配置多数据源 MultipleDataSource--> <bean name="dynamicDatasource" class="com.zzxw.web.common.DynamicDataSource"> <property name="targetDataSources"> <map> <!-- key和value-ref尽量保持一致,我在测试的时候因为名称不一致一致报错, 找了好久都没找到原因,最后统一了名称终于成功启动了 --> <entry key="dataSourceA" value-ref="dataSourceA"></entry> <entry key="dataSourceB" value-ref="dataSourceB"></entry> </map> </property> <!-- 指定一个默认的数据源,即在不需要切换数据源时,本地系统默认使用的数据源 --> <property name="defaultTargetDataSource" ref="dataSourceA" /> </bean> <bean id="dataSourceAspect" class="com.zzxw.web.common.DataSourceAspect"/> <aop:config> <aop:aspect ref="dataSourceAspect"> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.zzxw.web.*.mapper.*.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config><!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 --> <bean id="sqlSessionTemplate" class="com.zzxw.web.common.CustomSqlSessionTemplate" scope="prototype"> <!-- 构造注入参数指定本地默认数据源对应的SqlSessionFactoryBean --> <constructor-arg ref="sqlSessionFactory_A" /> <property name="targetSqlSessionFactorys"> <map> <!-- key和上文配置的数据源的id值尽量保持一致,我在测试的时候因为名称不一致一致报错, 找了好久都没找到原因,最后统一了名称终于成功启动了 --> <entry value-ref="sqlSessionFactory_A" key="dataSourceA"/> <entry value-ref="sqlSessionFactory_B" key="dataSourceB"/> </map> </property> </bean> <!-- MyBatis 动态扫描 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.zzxw.web.**.mapper"/> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/> </bean> <!-- 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" /> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dynamicDatasource"/> <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> <!-- AUTO->`0`("数据库ID自增") INPUT->`1`(用户输入ID") ID_WORKER->`2`("全局唯一ID") UUID->`3`("全局唯一ID") --> <property name="idType" value="3" /> <!-- MYSQL->`mysql` ORACLE->`oracle` DB2->`db2` H2->`h2` HSQL->`hsql` SQLITE->`sqlite` POSTGRE->`postgresql` SQLSERVER2005->`sqlserver2005` SQLSERVER->`sqlserver` --> <!-- Oracle需要添加该项 --> <property name="dbType" value="oracle" /> <!-- 全局表为下划线命名设置 true --> <property name="dbColumnUnderline" value="true" /> </bean>

7:mybatis-config.

<? plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下: | properties?, settings?, | typeAliases?, typeHandlers?, | objectFactory?,objectWrapperFactory?, | plugins?, | environments?, databaseIdProvider?, mappers? |--><configuration> <!--  | 全局配置设置  |  | 可配置选项     默认值,  描述  |  | aggressiveLazyLoading  true,  当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。  | multipleResultSetsEnabled true,  允许和不允许单条语句返回多个数据集(取决于驱动需求)  | useColumnLabel    true,  使用列标签代替列名称。不同的驱动器有不同的作法。参考一下驱动器文档,或者用这两个不同的选项进行测试一下。  | useGeneratedKeys   false, 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  | autoMappingBehavior   PARTIAL, 指定MyBatis 是否并且如何来自动映射数据表字段与对象的属性。PARTIAL将只自动映射简单的,没有嵌套的结果。FULL 将自动映射所有复杂的结果。  | defaultExecutorType   SIMPLE, 配置和设定执行器,SIMPLE 执行器执行其它语句。REUSE 执行器可能重复使用prepared statements 语句,BATCH执行器可以重复执行语句和批量更新。  | defaultStatementTimeout  null,  设置一个时限,以决定让驱动器等待数据库回应的多长时间为超时  | --> <settings>  <!-- 这个配置使全局的映射器启用或禁用缓存 -->  <setting name="cacheEnabled" value="true"/>  <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->  <setting name="lazyLoadingEnabled" value="true"/>  <setting name="multipleResultSetsEnabled" value="true"/>  <setting name="useColumnLabel" value="true"/>  <setting name="defaultExecutorType" value="REUSE"/>  <setting name="defaultStatementTimeout" value="25000"/>   <setting name="callSettersOnNulls" value="true"/>  </settings></configuration>

8:spring.

 <!-- 引入属性文件 --> <context:property-placeholder location="classpath:config.properties"/> <!-- Service包(自动注入) --> <context:component-scan base-package="com.zzxw.web.service"/> <import resource="classpath:spring/spring-mybatis.

9.CustomSqlSessionTemplate.java

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(DynamicDataSourceHolder.getDataSource());  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());   }  } } }

多数据源切换代码

1、DynamicDataSource.java

public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() {  // 从自定义的位置获取数据源标识  return DynamicDataSourceHolder.getDataSource(); }}

2、DataSourceAspect.java

public class DataSourceAspect { /**  * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源  *  * @param point  * @throws Exception  */ public void intercept(JoinPoint point) throws Exception {  Class<?> target = point.getTarget().getClass();  MethodSignature signature = (MethodSignature) point.getSignature();  // 默认使用目标类型的注解,如果没有则使用其实现接口的注解  for (Class<?> clazz : target.getInterfaces()) {   resolveDataSource(clazz, signature.getMethod());  }  resolveDataSource(target, signature.getMethod()); } /**  * 提取目标对象方法注解和类型注解中的数据源标识  *  * @param clazz  * @param method  */ private void resolveDataSource(Class<?> clazz, Method method) {  try {   Class<?>[] types = method.getParameterTypes();   // 默认使用类型注解   if (clazz.isAnnotationPresent(DataSource.class)) {    DataSource source = clazz.getAnnotation(DataSource.class);    DynamicDataSourceHolder.setDataSource(source.value());   }   // 方法注解可以覆盖类型注解   Method m = clazz.getMethod(method.getName(), types);   if (m != null && m.isAnnotationPresent(DataSource.class)) {    DataSource source = m.getAnnotation(DataSource.class);    DynamicDataSourceHolder.setDataSource(source.value());   }  } catch (Exception e) {   System.out.println(clazz + ":" + e.getMessage());  } }}

3、DynamicDataSourceHolder.java

public class DynamicDataSourceHolder { /**  * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰  */ private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>(); public static String getDataSource() {  return THREAD_DATA_SOURCE.get(); } public static void setDataSource(String dataSource) {  THREAD_DATA_SOURCE.set(dataSource); } public static void clearDataSource() {  THREAD_DATA_SOURCE.remove(); }}

 

原标题:spring+springmvc+mybatis+oracle+atomikos+jta实现多数据源事务管理

关键词:Spring

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

可能感兴趣文章

我的浏览记录