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. javaScript-进阶篇(一)

    1.变量 1.必须以字母.下划线或美元符号开头,后面可以跟字母.下划线.美元符号和数字. 2.变量名区分大小写,如:A与a是两个不同变量. 3.不允许使用JavaScript关键字和保留字做变量名. ...

  2. hihocoder-1284 机会渺茫(水题)

    机会渺茫 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近在追求一名学数学的女生小Z.小Z其实是想拒绝他的,但是找不到好的说辞,于是提出了这样的要求:对于给定的两 ...

  3. 【leetcode刷题笔记】Recover Binary Search Tree

    Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...

  4. PPAS数据库备份与恢复

    PPAS数据库备份不同于普通的Postgresql数据库的备份,因为PPAS数据库是兼容Oracle数据库的,所以会涉及到同义词.包.存储过程等,这个时候用Postgresql社区的备份与恢复工具时, ...

  5. Linux下视频流媒体直播服务器搭建详解

    目标: 搭建网络直播流媒体服务器系统(Linux操作系统) 背景: 用于OTT-TV大并发的直播和点播的一套流媒体服务器系统.支持N x 24小时录制回看和直播的服务器端解决方案. 解决方案: l  ...

  6. ACM学习历程—CSU 1216 异或最大值(xor && 贪心 && 字典树)

    题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1216 题目大意是给了n个数,然后取出两个数,使得xor值最大. 首先暴力枚举是C(n,  ...

  7. android开发中 解决服务器端解析MySql数据时中文显示乱码的情况

    首先,还是确认自己MySql账户和密码 1.示例  账户:root   密码:123456   有三个字段   分别是_id  .username(插入有中文数据).password 1)首先我们知道 ...

  8. shock编程

    Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socket ...

  9. MyBatis总结(1)

    MyBatis前身是ibatis,是一个数据持久层框架.封装优化了普通JDBC过程, 如数据库连接的创建.设置SQL语句参数.执行SQL语句.事务.结果映射以及资源释放等. MyBatis是一个支持普 ...

  10. Java探索之旅(3)——选择与循环

    1.选择结构与输出 ❶Switch语句: Switch表达式必须算出 char,byte,short,int类型数值之一,总是括号括住:Value1----ValueN,对应有相同数据类型且为常量或者 ...