使用Spring 提供的 AbstractRoutingDataSource 实现

创建 AbstractRoutingDataSource 实现类,负责保存所有数据源与切换数据源策略:
public class DynamicDataSource extends AbstractRoutingDataSource {

@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDatasourceKey();
}
}
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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

<bean id="dynamicDataSource" class="spring.dbs.DynamicDataSource">
<property name="defaultTargetDataSource" ref="primaryDataSource"/>
<property name="targetDataSources">
<map>
<entry key="primaryDataSource" value-ref="primaryDataSource"></entry>
<entry key="secondaryDataSource" value-ref="secondaryDataSource"></entry>
<entry key="thirdlyDataSource" value-ref="thirdlyDataSource"></entry>
</map>
</property>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="batch*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="persist*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="merge*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="query*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="load*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* spring.service..*(..))"/>
<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/>
</aop:config>
</beans>

看 DataSourceContextHolder实现,负责处理切换数据源策略的key,使用ThreadLocal确保线程隔离:
public class DataSourceContextHolder {

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

/**
* 设置 datasourceKey
*
* @param datasourceKey
*/
public static void setDatasourceKey(String datasourceKey) {
DATASOURCE_KEY.set(datasourceKey);
}

/**
* 获取 datasourceKey
*
* @return
*/
public static String getDatasourceKey() {
return DATASOURCE_KEY.get();
}

/**
* 删除 datasourceKey
*/
public static void clearDatasourceKey() {
DATASOURCE_KEY.remove();
}
}

使用Aop实现策略,实现动态切换数据源:
@Component
@Aspect
public class DatasourceHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(DatasourceHandler.class);

private static final String[] DATASOURCES = new String[]{"primaryDataSource", "secondaryDataSource", "thirdlyDataSource"};

① @Pointcut("execution(* spring.service..*(..))")
public void datasourcePoint() {
}

@Around("datasourcePoint()")
public Object handler(ProceedingJoinPoint point) throws Throwable {
LOGGER.info("begin get datasource......");
Object[] args = point.getArgs();
if (null != args && args.length > 0) {
② String key = String.valueOf(args[0]);
// 存入key
③ DataSourceContextHolder.setDatasourceKey(getKey(key));
}
Object result = point.proceed();
// 清除key
④ DataSourceContextHolder.clearDatasourceKey();
LOGGER.info("end get datasource......");
return result;
}

/**
* 获取key方法
*
* @param key
* @return
*/
private String getKey(String key) {
LOGGER.info("this key is : [ " + key + " ]!");
CRC32 crc = new CRC32();
crc.update(key.getBytes(StandardCharsets.UTF_8));
long result = crc.getValue();
LOGGER.info("this key's crc32 is : [ " + result + " ]!");
int index = (int) (result % 3);
LOGGER.info("this key's module is : [ " + index + " ]!");
int len = DATASOURCES.length;
if (index > (len - 1)) {
index = len - 1;
}
LOGGER.info("this key's result module is : [ " + index + " ]!");
String datasourceKey = DATASOURCES[index];
LOGGER.info("this datasource key is : [ " + datasourceKey + " ]!");
return datasourceKey;
}
}
①所有service包下的方法执行策略;
②demo默认使用第一个参数做为key;
③使用CRC32取模,获取数据源key,保存到DataSourceContextHolder.ThreadLocal.DATASOURCE_KEY 中,确保不同线程策略正确;
④业务逻辑处理完后,清除key;

使用JdbcTemplate,配置如下:
@Configuration
public class JdbcTemplateBean {

@Autowired
@Qualifier("dynamicDataSource")
private DataSource dynamicDataSource;

@Bean(name = "dynamicJdbcTemplate")
@Qualifier("dynamicJdbcTemplate")
public NamedParameterJdbcTemplate primaryJdbcTemplate() {
return new NamedParameterJdbcTemplate(dynamicDataSource);
}
}

使用过程中发现一问题,当事务配置为 propagation="REQUIRED"时,因为 Aop顺序问题导致先寻找数据源开启事务,后执行数据源切换策略,此时使用 <aop:advisor order="2"/>属性配置事务顺序为2,并使用 org.springframework.core.Ordered接口,设置策略执行顺序为1,保证策略执行在寻找数据源之前,具体如下:
事务切面配置:
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* spring.service..*(..))"/>
<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice" order="2"/>
</aop:config>
策略执行切面:
@Component
@Aspect
public class DatasourceHandler implements Ordered {

@Pointcut("execution(* spring.service..*(..))")
public void datasourcePoint() {
}

@Around("datasourcePoint()")
public Object handler(ProceedingJoinPoint point) throws Throwable {
// 策略实现
}

@Override
public int getOrder() {
return 1;
}
}

spring AbstractRoutingDataSource实现动态数据源切换的更多相关文章

  1. Spring(AbstractRoutingDataSource)实现动态数据源切换--转载

    原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目 ...

  2. Spring(AbstractRoutingDataSource)实现动态数据源切换

    转自: http://blog.51cto.com/linhongyu/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中切换数据源,直 ...

  3. SpringMVC 利用AbstractRoutingDataSource实现动态数据源切换

    SpringMVC 利用AbstractRoutingDataSource实现动态数据源切换 本文转载至:http://exceptioneye.iteye.com/blog/1698064 Spri ...

  4. AbstractRoutingDataSource 实现动态数据源切换原理简单分析

    AbstractRoutingDataSource 实现动态数据源切换原理简单分析 写在前面,项目中用到了动态数据源切换,记录一下其运行机制. 代码展示 下面列出一些关键代码,后续分析会用到 数据配置 ...

  5. dubbo服务+Spring事务+AOP动态数据源切换 出错

    1:问题描述,以及分析 项目用了spring数据源动态切换,服务用的是dubbo.在运行一段时间后程序异常,更新操作没有切换到主库上. 这个问题在先调用读操作后再调用写操作会出现. 经日志分析原因: ...

  6. AbstractRoutingDataSource实现动态数据源切换 专题

    需求:系统中要实现切换数据库(业务数据库和his数据库) 网上很多资料上有提到AbstractRoutingDataSource,大致是这么说的 在Spring 2.0.1中引入了AbstractRo ...

  7. 利用AbstractRoutingDataSource实现动态数据源切换

    需求:系统中要实现切换数据库(业务数据库和his数据库) 网上很多资料上有提到AbstractRoutingDataSource,大致是这么说的 在Spring 2.0.1中引入了AbstractRo ...

  8. Spring 实现动态数据源切换--转载 (AbstractRoutingDataSource)的使用

    [参考]Spring(AbstractRoutingDataSource)实现动态数据源切换--转载 [参考] 利用Spring的AbstractRoutingDataSource解决多数据源的问题 ...

  9. 【Spring】使用Spring的AbstractRoutingDataSource实现多数据源切换

    最近因为项目需要在做两个项目间数据同步的需求,具体是项目1的数据通过消息队列同步到项目2中,因为这个更新操作还涉及到更新多个库的数据,所以就需要多数据源切换的操作.下面就讲讲在Spring中如何进行数 ...

随机推荐

  1. 使用FIO测试磁盘iops

    我们如何衡量一个存储的性能呢?IOPS(Input/Output OperationsPer Second),即每秒进行读写(I/O)操作的次数是国际上通用的存储性能衡量标准,IOPS越高意味着在同一 ...

  2. jquery 获取和设置Select选项常用方法总结

    1.获取select 选中的 text:$("#cusChildTypeId").find("option:selected").text();$(" ...

  3. 显示Audio CD的音轨时间

    uses   MMSystem; procedure TForm1.Timer1Timer(Sender: TObject);var  Trk : Word;  Min : Word;  Sec : ...

  4. 在spring MVC 中关于session失效的判断 有一个类SessionStatus

    SessionStatus status 表示的是当前Session的状态  status.isComplete()-->为true时,表示当前Session还未过期;-->false,表 ...

  5. scala spark rdd转数据框

    1. http://blog.csdn.net/lw_ghy/article/details/51480358

  6. NavMesh KeyNote

    [NavMesh KeyNote] 1.NavMesh.CalculatePath(srcPos, desPos) 若srcPos,desPos相等,则CalculatePath返回false. 2. ...

  7. TensorFlow—CNN—CIFAR数据集分类

  8. SpringMVC入门(基于XML方式实现)

    ----------------------siwuxie095 SpringMVC 入门(基于 XML 方式实现) (一)搭建 SpringMVC 环境 1.先下载相关库文件,下载链接: (1)ht ...

  9. SSH三大框架需要的jar包

    1. Struts2框架 * struts-2.3.24\apps\struts2-blank\WEB-INF\lib\*.jar -- Struts2需要的所有jar包 * struts2-spri ...

  10. linq to sql之like

    contains——like '%提交%' StartsWith—— like '条件%' EndWith——like '%条件'