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. Selenium-使用firepath识别元素

    利用firepath进行元素识别提前已经安装好firebug和firepath 比如,打开http://www.baidu.com 1.按下F12 2.点击如图的位置 3.选择元素,可以定位出元素的属 ...

  2. Java 对象引用以及对象赋值

    一.Vehicle veh1 = new Vehicle(); 通常这条语句执行的动作被称为创建一个对象,其实他包含了四个动作. 1.new Vehicle  :表示在堆空间内创建了一个Vehicle ...

  3. Oracle修改字段名、字段数据类型

    语句:alter table tableName rename column oldCName to newCName; -- 修改字段名alter table tableName modify (c ...

  4. freeMarker(十五)——XML处理指南之声明的XML处理

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.基本内容 因为XML处理的方法非常必要--这在前面章节中已经展示- ...

  5. luogu2622开灯问题2

    #include<iostream> #include<cstdlib> #include<algorithm> #include<cstdio> #i ...

  6. ACM学习历程—HDU 5446 Unknown Treasure(数论)(2015长春网赛1010题)

    Problem Description On the way to the next secret treasure hiding place, the mathematician discovere ...

  7. Django学习(1)——python manage.py startapp app-name新建app报错问题

    作为一个刚接触python的小白,开始学习Django注定前路漫漫,记录一下学习过程中的问题和解决方案. 感谢“自强学堂”的无私奉献,根据教程安装了Django 1.9.12后,尝试新建项目,此时使用 ...

  8. BZOJ3401:[USACO2009MAR]Look Up

    浅谈栈:https://www.cnblogs.com/AKMer/p/10278222.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id ...

  9. nginx与apache 限制ip连接数和带宽方法

    今天有个人问我,nginx怎么限制ip连接数,突然想不起来了,年龄大了,脑子不怎么好使了.还要看一下配置才想起了.那个人又问我,你测试过的吗?一下子把我问蒙了,我真没测试过了,也不知道启作用了没有. ...

  10. TreeSet 和TreeMap 排序

    TreeSet 有两种排序方式 1. Java.lang.Comparble+compareTo new TreeSet() 用这种方法必须要求实体类实现Comparable接口,也就是说要求添加到T ...