博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【spring】spring boot多数据源配置(方式二)
阅读量:4080 次
发布时间:2019-05-25

本文共 5227 字,大约阅读时间需要 17 分钟。

上篇文章讲述了一种简单粗暴的多数据源配置方式,这篇来讲一下动态切换数据源的方式配置。

动态切换数据源,其核心在于一个AbstractRoutingDataSource类,通过继承此类并重写determineCurrentLookupKey方法可以实现动态切换数据源,具体切换方式可点进去看源码的determineTargetDataSource方法,比较简单,这里只记录实现。

数据库准备

参考上篇文章:http://www.scarlettbai.com/index.php/archives/112.html

动态数据源配置

public class MyDynamicDataSource extends AbstractRoutingDataSource {
@Override protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.get(); }}

这个方法的返回值,就是一个数据源的key,我们对于多个数据源,会对每个数据源定义一个key,之后以map形式保存在AbstractRoutingDataSource的targetDataSources属性中。

接下来看一下上文中出现的DynamicDataSourceContextHolder类:

public class DynamicDataSourceContextHolder {
private static ThreadLocal
DBNAME = new ThreadLocal<>(); public static String get() {
return DBNAME.get(); } public static void set(String dbName) {
DBNAME.set(dbName); } public static void clear() {
DBNAME.remove(); }}

DynamicDataSourceContextHolder类的作用很简单,就是根据线程来存取数据库的key。

DataSource配置

@Configurationpublic class DataSourceConfig {
@Autowired private Environment env; @Bean public DataSource backDataSource() {
DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(env.getProperty("spring.datasource.back.jdbcUrl")); dataSource.setUsername(env.getProperty("spring.datasource.back.username")); dataSource.setPassword(env.getProperty("spring.datasource.back.password")); return dataSource; } @Bean public DataSource frontDataSource() {
DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(env.getProperty("spring.datasource.front.jdbcUrl")); dataSource.setUsername(env.getProperty("spring.datasource.front.username")); dataSource.setPassword(env.getProperty("spring.datasource.front.password")); return dataSource; } @Bean @Primary public DataSource dynamicDataSource() {
MyDynamicDataSource dataSource = new MyDynamicDataSource(); dataSource.setDefaultTargetDataSource(frontDataSource()); Map
allDataSource = new HashMap<>(); allDataSource.put("backDataSource", backDataSource()); allDataSource.put("frontDataSource", frontDataSource()); dataSource.setTargetDataSources(allDataSource); return dataSource; }}

这里datasource配置引入了阿里的druid数据源,各位不用的话可以切换为自己的数据源即可,主要注意一下dynamicDataSource这个数据源,这里需要将他设置为主数据源,即@Primary。之后调用数据源都会走determineTargetDataSource进行数据源路由切换。

在调用dao前进行数据源切换

这里通过AOP方式实现,看各人系统需求,可以直接通过aop扫描对应的分包目录,也可以自定义一个注解来自己在方法上添加注解。

//定义注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface DynamicDataSource {
/** * dbname * @return */ String value();}//AOP实现@Aspect@Componentpublic class DynamicDataSourceAOP {
@Before("@annotation(org.white.mutidatasource2.aop.DynamicDataSource)") public void changeDataSource(JoinPoint point) {
Class
clazz = point.getTarget().getClass(); MethodSignature signature = (MethodSignature) point.getSignature(); try {
Method method = clazz.getDeclaredMethod(signature.getName(), signature.getParameterTypes()); if (method.isAnnotationPresent(DynamicDataSource.class)) {
DynamicDataSource dynamicDataSource = method.getAnnotation(DynamicDataSource.class); String dbName = dynamicDataSource.value(); if (DynamicDataSourceContextAware.names.contains(dbName)) {
DynamicDataSourceContextHolder.set(dbName); } } } catch (Exception e) {
System.out.println("error" + e.getMessage()); } } @After("@annotation(org.white.mutidatasource2.aop.DynamicDataSource)") public void after() {
DynamicDataSourceContextHolder.clear(); }}

这里的aop实现也很简单,就是通过读取注解内容来切换DynamicDataSourceContextHolder中的值。

其中的DynamicDataSourceContextAware类代码如下,只是记录一个names的集合,可以看需求省略:

@Componentpublic class DynamicDataSourceContextAware implements ApplicationContextAware {
public static Set
names = new HashSet<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map
dataSources = applicationContext.getBeansOfType(DataSource.class); for (String dataSourceName : dataSources.keySet()) {
if (!"dynamicDataSource".equals(dataSourceName)) {
names.add(dataSourceName); } } }}

最后,来看一下调用方式:

@Servicepublic class BizServiceImpl implements BizService {
@Autowired private AdminMapper adminMapper; @Autowired private UserMapper userMapper; //无注解,使用默认datasource @Override public int addUser(UserDTO userDTO) {
return userMapper.insert(userDTO); } //使用backDatasource @Override @DynamicDataSource(value = "backDataSource") public int addAdmin(AdminDTO adminDTO) {
return adminMapper.insert(adminDTO); }}

实现过程就在这里了,其核心其实就是一个AbstractRoutingDataSource类,其他都是一些spring的基础知识。

这种模式优点在于扩展方便,新增数据源只需新增一个datasource的配置即可。

另外这里附上github项目地址:https://github.com/whiteBX/mutidatasource2

可以直接下载运行,包括初始化sql都在项目内。

转载地址:http://xhsni.baihongyu.com/

你可能感兴趣的文章
SQL语句(二)查询语句
查看>>
SQL语句(六) 自主存取控制
查看>>
《计算机网络》第五章 运输层 ——TCP和UDP 可靠传输原理 TCP流量控制 拥塞控制 连接管理
查看>>
堆排序完整版,含注释
查看>>
二叉树深度优先遍历和广度优先遍历
查看>>
生产者消费者模型,循环队列实现
查看>>
PostgreSQL代码分析,查询优化部分,process_duplicate_ors
查看>>
PostgreSQL代码分析,查询优化部分,canonicalize_qual
查看>>
PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors()
查看>>
IA32时钟周期的一些内容
查看>>
获得github工程中的一个文件夹的方法
查看>>
《PostgreSQL技术内幕:查询优化深度探索》养成记
查看>>
PostgreSQL查询优化器详解之逻辑优化篇
查看>>
STM32中assert_param的使用
查看>>
C语言中的 (void*)0 与 (void)0
查看>>
vu 是什么
查看>>
io口的作用
查看>>
IO口的作用
查看>>
UIView的使用setNeedsDisplay
查看>>
归档与解归档
查看>>