11

//定义数据源枚举
public enum DataSourceKey {
master,
slave,
}

22

/**
* 数据源路由
*/
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
log.error("Current DataSource is [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey();
} }
/**
* 数据源路由holder
*/
@Slf4j
public class DynamicDataSourceContextHolder {
private static int counter = 0; private static final ThreadLocal<String> CONTEXT_HOLDER = ThreadLocal.withInitial(DataSourceKey.master::name); /**
* 所有数据源key
*/
public static List<Object> dataSourceKeys = new ArrayList<>(); /**
* 从数据源key
*/
public static List<Object> slaveDataSourceKeys = new ArrayList<>(); /**
*
* set数据源
*/
public static void setDataSourceKey(String key) {
CONTEXT_HOLDER.set(key);
} /**
* get数据源
*/
public static String getDataSourceKey() {
return CONTEXT_HOLDER.get();
}
/**
* 主数据源
*/
public static void useMasterDataSource() {
CONTEXT_HOLDER.set(DataSourceKey.master.name());
} /**
* 从数据源
*/
public static void useSlaveDataSource() {
try {
int datasourceKeyIndex = counter % slaveDataSourceKeys.size();//负载均衡-轮询
CONTEXT_HOLDER.set(String.valueOf(slaveDataSourceKeys.get(datasourceKeyIndex)));
counter++;
} catch (Exception e) {
log.error("Switch slave datasource failed, error message is {}", e.getMessage());
useMasterDataSource();
e.printStackTrace();
}
} public static void clearDataSourceKey() {
CONTEXT_HOLDER.remove();
} public static boolean containDataSourceKey(String key) {
return dataSourceKeys.contains(key);
} }

33

@Configuration
@MapperScan(basePackages = "com.buyi.mytransaction.dao.one", sqlSessionFactoryRef = "mybatisSqlSessionFactoryOne")
public class MyDynamicMybatisDataSource { @Bean(name = "master")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.one.master", ignoreInvalidFields = true)
public DataSource master() {
return new DruidDataSource();
} @Bean(name = "slave")
@ConfigurationProperties(prefix = "spring.datasource.one.slave", ignoreInvalidFields = true)
public DataSource slave() {
return new DruidDataSource();
} @Bean("dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(4);
dataSourceMap.put(DataSourceKey.master.name(), master());
dataSourceMap.put(DataSourceKey.slave.name(), slave()); dynamicRoutingDataSource.setDefaultTargetDataSource(master());//默认数据源
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);//数据源 DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSourceMap.keySet());//所有数据源
DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());//设置从数据源
DynamicDataSourceContextHolder.slaveDataSourceKeys.remove(DataSourceKey.master.name());
return dynamicRoutingDataSource;
} //事务管理器
@Bean(name = "mybatisTransactionManagerOne")
@Primary
public DataSourceTransactionManager mybatisTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
} //会话工厂
@Bean("mybatisSqlSessionFactoryOne")
@Primary
public SqlSessionFactory mybatisSqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sf = new SqlSessionFactoryBean();
sf.setDataSource(dataSource);
sf.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:repository/one/**/*Mapper.xml")); //自动转驼峰 resultType="***"
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
sf.setConfiguration(configuration);
return sf.getObject();
} }

44

@Slf4j
@Aspect
@Component
public class DynamicDataSourceAspect { private final String[] QUERY_PREFIX = {"select","query"}; @Pointcut("execution( * com.buyi.mytransaction.dao.one.*.*(..))")
public void daoAspect() {
} /**
* 切换数据源
*/
@Before("daoAspect()")
public void switchDataSource(JoinPoint point) {
Boolean isQueryMethod = isQueryMethod(point.getSignature().getName());
if (isQueryMethod) {
DynamicDataSourceContextHolder.useSlaveDataSource();
log.debug("Switch DataSource to [{}] in Method [{}]",
DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature());
}
} /**
* 重置数据源
*/
@After("daoAspect())")
public void restoreDataSource(JoinPoint point) {
DynamicDataSourceContextHolder.clearDataSourceKey();
log.debug("Restore DataSource to [{}] in Method [{}]",
DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature());
} private Boolean isQueryMethod(String methodName) {
for (String prefix : QUERY_PREFIX) {
if (methodName.startsWith(prefix)) {
return true;
}
}
return false;
}
}
    @Test
//测试切换数据源
public void test3() {
Company c = Company.builder().companyId("789").companyName("百度").memo("人工智能").build();
oneCompanyservice.oneInsert(c); List<Company> companyList = oneCompanyservice.selectAll();
for (Company company : companyList) {
System.out.println(company);
//Company(companyId=999, companyName=百度子公司, memo=111)
//此条数据在从数据库中已存在
}
}

Spring动态切换数据源的更多相关文章

  1. Spring动态切换数据源及事务

    前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...

  2. spring动态切换数据源(一)

    介绍下spring数据源连接的源码类:| 1 spring动态切换连接池需要类AbstractRoutingDataSource的源码 2 /* 3 * Copyright 2002-2017 the ...

  3. Spring AOP动态切换数据源

    现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...

  4. Spring + Mybatis 项目实现动态切换数据源

    项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...

  5. Spring+Mybatis动态切换数据源

    功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...

  6. Spring动态切换多数据源事务开启后,动态数据源切换失效解决方案

    关于某操作中开启事务后,动态切换数据源机制失效的问题,暂时想到一个取巧的方法,在Spring声明式事务配置中,可对不改变数据库数据的方法采用不支持事务的配置,如下: 对单纯查询数据的操作设置为不支持事 ...

  7. Spring Boot 如何动态切换数据源

    本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...

  8. 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法

    相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...

  9. Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

随机推荐

  1. Mysql总结_03_mysql常用命令

    一.MySQL服务的启动和停止 net stop mysql net start mysql 二.登陆mysql mysql -u用户名 -p用户密码 键入命令mysql -uroot -p, 回车后 ...

  2. Json解析方式

    http://blog.sina.com.cn/s/blog_628cc2b70101dydc.html

  3. [BZOJ2806][CTSC2012]熟悉的文章(Cheat)

    bzoj luogu 题目描述 阿米巴是小强的好朋友. 在小强眼中,阿米巴是一个作文成绩很高的文艺青年.为了获取考试作文的真谛,小强向阿米巴求教.阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么 ...

  4. 立方体贴图(Cubemap)

    http://blog.csdn.net/asdjy123/article/details/51190643 点击打开链接 好东西保存方便查看 立方体贴图(Cubemap) 原文 Cubemaps 作 ...

  5. Android的Notification相关设置

    Android手机:三星Galaxy S6 Android版本:Android 7.0 Android系统自带的本地通知会从顶部Pop下来,用来提示用户有新的消息,然后在Notification栏中停 ...

  6. cloudera上面安装Spark2.0

    Cloudera默认值是提供Spark1.6的安装,下面介绍如何来安装spark2.1 1. csd包:http://archive.cloudera.com/spark2/csd/ 2. parce ...

  7. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

  8. keepalive安装和配置

    1.下载安装包并解压 sudo wget http://www.keepalived.org/software/keepalived-1.2.13.tar.gz tar zxvf keepalived ...

  9. 实用的原生js图片轮播

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. Netty组件

    一.Channel.EventLoop 和ChannelFuture 这些类合在一起,可以被认为是Netty 网络抽象的代表: Channel—Socket: EventLoop—控制流.多线程处理. ...