spring+atomikos+mybatis 多数据源事务(动态切换)
注:自动切换,是为不同的数据源,却要对应相同的dao层;
1.与无事务版的一样,创建DynamicDataSource类,继承AbstractRoutingDataSource
package com.test.main.dataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
创建辅助类DynamicDataSourceHolder,主要用于保存当前线程所需的datasource的key值
package com.test.main.dataSource;
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();
}
}
创建dao层切面,注解选择数据源DataSourceAspect类:
package com.test.main.dataSource; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component; import com.test.main.annotations.DataSource; @Component
@Aspect
public class DataSourceAspect {
@Before("execution(* com.test.model.dao.*.*.*(..))")
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()); }
private void resolveDataSource(Class<?> clazz, Method method) {
String sourceName = null;
try {
Class<?>[] types = method.getParameterTypes();
if (clazz.isAnnotationPresent((Class<? extends Annotation>) DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
sourceName = source.value();
DynamicDataSourceHolder.setDataSource(sourceName);
}
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
sourceName = source.value();
DynamicDataSourceHolder.setDataSource(sourceName);
}
} catch (Exception e) {
System.out.println(clazz + ":" + e.getMessage());
}
} }
2.spring-db.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:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
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.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> <util:properties id="jdbc"
location="classpath:etc/mybatis/db.properties" /> <!-- 连接池配置开始 -->
<bean id="base" class="com.alibaba.druid.pool.xa.DruidXADataSource"
destroy-method="close" lazy-init="true">
<property name="initialSize" value="5" />
<property name="minIdle" value="5" />
<property name="maxActive" value="20" /> <property name="validationQuery" value="SELECT 1" />
<property name="timeBetweenEvictionRunsMillis" value="2800000" />
<property name="minEvictableIdleTimeMillis" value="600000" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="filters" value="stat" /> <property name="logAbandoned" value="true" />
</bean> <!-- Druid连接池 -->
<bean id="jpcar" parent="base">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.jpcar_url}" />
<property name="username" value="#{jdbc.username}" />
<property name="password" value="#{jdbc.password}" />
</bean>
<bean id="jpcarAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="mysql/jpcar" />
<property name="xaDataSource" ref="jpcar" />
<property name="maintenanceInterval" value="28000" />
<property name="testQuery" value="SELECT 1" />
</bean>
<bean id="jpcarData" parent="base">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.jpcarData_url}" />
<property name="username" value="#{jdbc.username}" />
<property name="password" value="#{jdbc.password}" />
</bean>
<bean id="jpcarDataAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="mysql/jpcarData" />
<property name="xaDataSource" ref="jpcarData" />
<property name="maintenanceInterval" value="28000" />
<property name="testQuery" value="SELECT 1" />
</bean> <bean id="test_jpcar" parent="base">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.test_jpcar_url}" />
<property name="username" value="#{jdbc.test_username}" />
<property name="password" value="#{jdbc.test_password}" /> </bean>
<bean id="test_jpcarAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="mysql/test_jpcar" />
<property name="xaDataSource" ref="test_jpcar" />
<property name="maintenanceInterval" value="28000" />
<property name="testQuery" value="SELECT 1" />
</bean>
<bean id="test_jpcarData" parent="base">
<property name="driverClassName" value="#{jdbc.driverClassName}" />
<property name="url" value="#{jdbc.test_jpcarData_url}" />
<property name="username" value="#{jdbc.test_username}" />
<property name="password" value="#{jdbc.test_password}" /> </bean>
<bean id="test_jpcarDataAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="mysql/test_jpcarData" />
<property name="xaDataSource" ref="test_jpcarData" />
<property name="maintenanceInterval" value="28000" />
<property name="testQuery" value="SELECT 1" />
</bean>
<!-- 连接池配置结束 --> <!-- MyBatis整合开始 --> <bean id="jpcarDataDynamicDataSource" class="com.jpcar.main.dataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="jpcar" value-ref="jpcarAtom"></entry>
<entry key="jpcarData" value-ref="jpcarDataAtom"></entry>
<entry key="test_jpcarData" value-ref="test_jpcarDataAtom"></entry>
<entry key="test_jpcar" value-ref="test_jpcarData"></entry>
</map>
</property>
</bean>
<bean id="jpcarDataFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="jpcarDataDynamicDataSource" />
<property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml" />
<property name="mapperLocations" value="classpath:com/**/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.jpcar" />
<property name="annotationClass" value="com.jpcar.main.annotations.MyBatisRepository" />
<property name="sqlSessionFactory" ref="jpcarDataFactory"></property>
<property name="sqlSessionFactoryBeanName" value="jpcarDataFactory"></property>
</bean> <!-- MyBatis整合结束 --> <!-- 配置数据库事务开始 -->
<!-- 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="90000" />
</bean>
<bean id="springTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref bean="atomikosTransactionManager" />
</property>
<property name="userTransaction">
<ref bean="atomikosUserTransaction" />
</property>
<property name="allowCustomIsolationLevels" value="true" />
</bean> <tx:annotation-driven transaction-manager="springTransactionManager" />
<!-- 配置数据库事务结束 --> </beans>
2.1在同一个事务中,不同的数据源需要不同 SqlSessionFactoryBean,注意配置时,需要配置 MapperScannerConfigurer的:
<property name="sqlSessionFactoryBeanName" value="cFactory"></property>
value值为:SqlSessionFactoryBean 的 bean id;
2.2同一事务中的SqlSessionFactoryBean,对应MapperScannerConfigurer 中的 basePackage 不能范围重合,不然在同一事务时,spring不会切换数据源,而是取先前与之重合的SqlSessionFactoryBean的数据源
spring+atomikos+mybatis 多数据源事务(动态切换)的更多相关文章
- 【原】通过AOP实现MyBatis多数据源的动态切换
[环境参数]1.开发框架:Spring + SpringMVC + MyBatis 2.数据库A的URL:jdbc.url=jdbc:mysql://172.16.17.164:3306/ test? ...
- spring+mybatis多数据源,动态切换
有时我们项目中需要配置多个数据源,不同的业务使用的数据库不同 实现思路:配置多个dataSource ,再配置多个sqlSessionFactory,和dataSource一一对应.重写SqlSess ...
- spring mvc+mybatis+多数据源切换
spring mvc+mybatis+多数据源切换,选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...
- Spring多数据源的动态切换
Spring多数据源的动态切换 目前很多项目中只能配置单个数据源,那么如果有多个数据源肿么办?Spring提供了一个抽象类AbstractRoutingDataSource,为我们很方便的解决了这个问 ...
- Spring简单实现数据源的动态切换
Spring简单实现数据源的动态切换: 1. 创建一个数据源切换类: 2. 继承AbstractRoutingDataSource,创建多数据源路由类,并注入到spring的配置文件中: 3. AOP ...
- spring与mybatis集成和事务控制
一个. 基本介绍 本文将使用spring整合mybatis, 并加入事务管理, 以此为记, 方便以后查阅. 二. 样例 1. 代码结构图: 2. 建表语句: DROP DATABASE test; C ...
- springboot 双数据源+aop动态切换
# springboot-double-dataspringboot-double-data 应用场景 项目需要同时连接两个不同的数据库A, B,并且它们都为主从架构,一台写库,多台读库. 多数据源 ...
- Spring Boot + Mybatis 多数据源配置实现读写分离
本文来自网易云社区 作者:王超 应用场景:项目中有一些报表统计与查询功能,对数据实时性要求不高,因此考虑对报表的统计与查询去操作slave db,减少对master的压力. 根据网上多份资料测试发现总 ...
- Spring配置多个数据源,并实现数据源的动态切换转载)
1.首先在config.properties文件中配置两个数据库连接的基本数据.这个省略了 2.在spring配置文件中配置这两个数据源: 数据源1 <!-- initialSize初始化时建立 ...
随机推荐
- java中Mysql开发
[IntelliJ IDEA 12使用]导入外部包 http://www.cnblogs.com/haochuang/p/3491959.html JDBC导入包即可 http://blog.163. ...
- 10.Android UiAutomator Junit 断言函数的使用
一.断言函数介绍 1.断言函数: 确定被测试的方法是否按照预期的效果正常工作 比如说: if (假设成立){ 通过测试 }else{ 报错并终止当前用例测试 } 2.断言函数用例结构: 一个完整的测试 ...
- WPF系列之二:解耦View层控件事件与ViewModel层事件的响应
以前的做法: 1.当项目的时间比较紧迫的时候,对UI层中控件的事件的处理,往往采取的是类似Winform中最简单的做法,直接做一个事件的Handler直接去调用VM层的方法. 2.控件只有一个Comm ...
- windows7中用vitualbox安装OS X 10.11 El Capitan 及 Xcode 7.0--转载
在 Win 7或8 下使用 VirtualBOX 虚拟机安装 OS X 10.11 El Capitan 及 Xcode 7.0 来源:http://bbs.feng.com/read-htm-tid ...
- 预处理 Gym - 101128H
题目链接:http://codeforces.com/gym/101128 题目大意:给你一个区间[x,y],找出这个区间有多少个seldom的数字. seldom的数字定义如下:该数值的二进制数字符 ...
- atcoder #082 E 暴力 计算几何
给出点集,然后求一个凸包的所有的子凸包的贡献总和,贡献计算是凸包内部含边界上点的数量N,凸包的不包含边界的顶点数S,贡献为$2^{N-S}$ 首先很容易想到,凸包上包含内部的所有点构成的子凸包有Sum ...
- eclipse中修改svn用户名和密码
开发中有时候用公共的电脑提交一些代码,eclipse没有专门的切换svn账户的功能.查阅资料得出解决办法: 1. 查看你的Eclipse 中使用的是什么SVN Interface windows & ...
- JAVA中反射机制六(java.lang.reflect包)
一.简介 java.lang.reflect包提供了用于获取类和对象的反射信息的类和接口.反射API允许对程序访问有关加载类的字段,方法和构造函数的信息进行编程访问.它允许在安全限制内使用反射的字段, ...
- java网络传输数据
网络文件传输的问题,实际也是一种IO读写的基本问题.对于网络的文件数据写入到服务器的进程中,然后把进程中的网络IO系统传递到客户机,这个阶段,数据以字节流的形式保存.当该字节流被客户进程接受后,客户进 ...
- 用C++写一个没人用的ECS
github地址:https://github.com/yangrc1234/Resecs 在做大作业的时候自己实现了一个简单的ECS,起了个名字叫Resecs. 这里提一下一些实现的细节,作为回顾. ...