Spring动态切换数据源
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动态切换数据源的更多相关文章
- Spring动态切换数据源及事务
前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...
- spring动态切换数据源(一)
介绍下spring数据源连接的源码类:| 1 spring动态切换连接池需要类AbstractRoutingDataSource的源码 2 /* 3 * Copyright 2002-2017 the ...
- Spring AOP动态切换数据源
现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...
- Spring + Mybatis 项目实现动态切换数据源
项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...
- Spring+Mybatis动态切换数据源
功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...
- Spring动态切换多数据源事务开启后,动态数据源切换失效解决方案
关于某操作中开启事务后,动态切换数据源机制失效的问题,暂时想到一个取巧的方法,在Spring声明式事务配置中,可对不改变数据库数据的方法采用不支持事务的配置,如下: 对单纯查询数据的操作设置为不支持事 ...
- Spring Boot 如何动态切换数据源
本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...
- 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法
相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...
- Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源
深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...
随机推荐
- Java_异常_01_org.apache.commons.lang.exception.NestableRuntimeException
异常信息: The type org.apache.commons.lang.exception.NestableRuntimeException cannot be resolved. It is ...
- JQuery表单验证插件EasyValidator
本插件的宗旨是:用户无需写一行JS验证代码,只需在要验证的表单中加入相应的验证属性即可,让验证功能易维护,可扩展,更容易上手. DEMO中已经包含了常用的正则表达式,可以直接复用,为了考虑扩展性,所以 ...
- codeforces 776C Molly's Chemicals(连续子序列和为k的次方的个数)
题目链接 题意:给出一个有n个数的序列,还有一个k,问在这个序列中有多少个子序列使得sum[l, r] = k^0,1,2,3…… 思路:sum[l, r] = k ^ t, 前缀和sum[r] = ...
- pyglet--EventLoop对象(主事件循环,用于从系统消息队列中取出消息,并派发给各个窗口)
一.识别系统消息,并派出该消息 EventLoop(应用程序的事件循环),用于循环的从系统消息队列中获取系统消息(包含消息的各种参数:如鼠标位置,事件类型,鼠标左右键,哪个键盘键等),然后派发相应的事 ...
- Mex混合编程专题一:Mex环境搭建
使用Matlab时间长了,难免会碰到使用mex文件的经历,不管是别人的还是自己的,就比如MatConvNet(http://www.vlfeat.org/matconvnet/)使用了混合编程的技术实 ...
- python suds 调用webservice 缓存
在linux系统中 如果webservice更新了字段 suds调用有可能缓存以前的字段或方法,对新的字段报找不到类型 TypeNotFound,或者对 新加的方法找不到该方法的错误. 当更新或添加w ...
- photonView 空指针异常
1.OBJ上要有PhotonView 脚本 2.PhotonNetwork.Instantiate方法初始化出来OBJ OBJ 预制体要放在Resources文件夹下 PhotonNetwork.In ...
- 非系统数据文件损坏,rman备份恢复
实验前提:已经做好备份. SQL> col file_name for a50select file_id,file_name from dba_data_files; FILE_ID FILE ...
- BZOJ1216:[HNOI2003]操作系统
我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem ...
- Centos6.5安装JDK8教程(一)
[原] 转载请注明原文地址, 保持对知识基本尊重,谢谢! Win7宿主系统 VmWareWorkstation 11应用下的 Centos6.5系统. /******************* ...