Spring多租户数据源管理AbstractRoutingDataSource_第1页
Spring多租户数据源管理AbstractRoutingDataSource_第2页
Spring多租户数据源管理AbstractRoutingDataSource_第3页
Spring多租户数据源管理AbstractRoutingDataSource_第4页
Spring多租户数据源管理AbstractRoutingDataSource_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第​​​​​​​Spring多租户数据源管理AbstractRoutingDataSource目录1.基本原理2.配置代码3.问题总结前言:

很多情况,我们确实需要在一个服务中访问多个数据源。虽然它让整体设计变的不那么优雅,但真实的世界确实需要它。比如,你的业务为两个比较大的客户服务,但你希望他们能够共用一套代码。

也就是说,你的代码刚开始没有考虑设计多租户这种功能,但后面又有这种蛋疼的需求。但还好不是爆炸式的租户增长。

除了引入一些分库分表组件,Spring自身提供了AbstractRoutingDataSource的方式,让多数数据源的管理成为可能。其实分库分表组件使用上限制很多,你不得不首先梳理这座屎山,接下来还要忍受中间件对你的SQL的苛刻要求;反而是一些野路子,能够让代码的改动量尽量的减少。

心动不如行动。接下来,就让我们来看一下它的具体实现吧。

1.基本原理

多数据源能进行动态切换的核心就是spring底层提供了AbstractRoutingDataSource类进行数据源路由。AbstractRoutingDataSource实现了DataSource接口,所以我们可以将其直接注入到DataSource的属性上。

我们主要继承这个类,实现里面的方法determineCurrentLookupKey(),而此方法只需要返回一个数据库的名称即可。

比如,Controller通过拿到前端业务传递的数值,进行业务逻辑分发。它就可以手动设置当前请求的数据库标识,然后路由到正确的库表里面。

@Controller

public

class

ARDTestController

{

@GetMapping("test")

public

void

chifeng(){

//db-a

应该是上层传递下来的属性,我们可以把它放在ThreadLocal里

DataSourceContextHolder.setDbKey("db-a");

}

}

那么当sql语句执行的时候,它如何知道自己需要切换到哪个数据源呢?是不是需要把db-a这个属性一直透传下去呢?

在Java中,可以使用ThreadLocal绑定这个透传的属性。像Spring的嵌套事务等实现的原理,也是基于ThreadLocal去运行的。所以,DataSourceContextHolder.本质上是一个操作ThreadLocal的类。

public

class

DataSourceContextHolder

{

private

static

InheritableThreadLocalString

dbKey

=

new

InheritableThreadLocal();

public

static

void

setDbKey(String

key){

dbKey.set(key);

}

public

static

String

getDbKey(){

return

dbKey.get();

}

}

2.配置代码

首先,我们自定义了配置文件的格式。如下面的代码,就配置了db-a和db-b两个数据库。

multi:

dbs:

db-a:

driver-class-name:

org.h2.Driver

url:

jdbc:h2:mem:dba;MODE=MYSQL;DATABASE_TO_UPPER=false;

db-b:

driver-class-name:

org.h2.Driver

url:

jdbc:h2:mem:dbb;MODE=MYSQL;DATABASE_TO_UPPER=false;

然后,我们将它解析称properties。

@ConfigurationProperties(prefix

=

"multi")

@Configuration

public

class

DbsProperties

{

private

MapString,

MapString,

String

dbs

=

new

HashMap();

public

MapString,

MapString,

String

getDbs()

{

return

dbs;

}

public

void

setDbs(MapString,

MapString,

String

dbs)

{

this.dbs

=

dbs;

}

}

接下来一步,需要配置整个应用所默认的数据源。如你所见,它的主要逻辑,就是在运行的时候,从ThreadLocal里取出提前设置的这个值。

public

class

DynamicDataSource

extends

AbstractRoutingDataSource

{

@Override

protected

Object

determineCurrentLookupKey()

{

return

DataSourceContextHolder.getDbKey();

}

}

最后一步,设置整个项目中默认的DataSource。注意,我们生成DynamicDataSource之后,还需要提供targetDataSource和defaultTargetDataSource两个属性的值,才能够正常运行。

@Configuration

public

class

DynamicDataSourceConfiguration

{

@Autowired

DbsProperties

properties;

@Bean

public

DataSource

dataSource(){

DynamicDataSource

dataSource

=

new

DynamicDataSource();

final

MapObject,Object

targetDataSource

=

getTargetDataSource();

dataSource.setTargetDataSources(targetDataSource);

//TODO

默认数据库需要设置

dataSource.setDefaultTargetDataSource(targetDataSource.values().iterator().next());

return

dataSource;

}

private

MapObject,Object

getTargetDataSource(){

MapObject,Object

dataSources

=

new

HashMap();

perties.getDbs().entrySet().stream()

.forEach(e-{

DriverManagerDataSource

dmd

=

new

DriverManagerDataSource();

dmd.setUrl(e.getValue().get("url"));

dmd.setDriverClassName(e.getValue().get("driver-class-name"));

dataSources.put(e.getKey(),dmd);

});

return

dataSources;

}

}

3.问题

通过以上简单的代码,就可以实现Spring简单的多数据源管理。但明显的,它还存在很多问题。

需要产品设计选择模式,进行业务切换。前端可以采用放在localStroage的方式,保存属性,可使用拦截器方式将变量每次都传递。后端每次请求,都需要带上目标db,可以采用放在ThreadLocal里的方式。但ThreadLocal有线程透传的问题,如果任务里开启了子线程,则变量不能共享。由于表是动态选择的,所以JPA自动创建和update等模式,将不可用。不方便测试和单元测试,在测试接口的时候,也需要每次强制指定指向的库。由于是修改数据源的模式,每次增加库,都需要重新启动上线才可以。如果要做到动态性,数据源销毁是个问题。

总结

对于一个微服务来说,有很多默认的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论