springboot多数据源配置实例

本文介绍了如何在SpringBoot应用中配置Mybatis的Mapper文件,重点讲解了如何配置多个数据源,包括自定义数据源名称、配置文件的引用、DataSourceType枚举、DataSourceUtil工具类以及如何动态选择和切换数据源。
摘要由CSDN通过智能技术生成

context-path: /db

指定Mybatis的Mapper文件

mybatis:

mapper-locations: classpath:mappers/*xml

type-aliases-package: jin.panpan.database.entity

#日志配置

logging:

config: classpath:log4j2.xml

复制代码

配置文件, 除了基本的应用名称、端口、路径、日志等配置以外, 主要看数据库驱动的配置, 这里我们不像平时的单数据源的配置, 我们需要配置多个数据源, 上面示例的配置文件里, 由两个注意点:

  • db1和db2是我们自定义的数据源名称, 这个我们在后面的MybatisConfig文件里会用到

  • 数据源里的配置jdbc-url对应单数据源配置里的url, 这里使用url会注入失败

  • ${db1.username}等是导入的application-jdbc.properties文件里的配置值

application-jdbc.properties

db1.username = user

db1.password =

db1.url = jdbc:mysql://xx.xx.xx.xx:3306/db1

db2.username = user

db2.password =

db2.url = jdbc:mysql://xx.xx.xx.xx:3306/db2

复制代码

key-value结构, key可以在引入此文件的配置里使用${key}引用

这里我们使用两个数据库, 但是数据库的表结构一致(至少多数据源涉及到的表需要结构一致), 以避免不能共用一套代码

DataSourceType

public enum DataSourceType {

//NONE用来返回默认

NONE(“”),

DB1(“db1”),

DB2(“db2”),

;

//省略部分代码

}

复制代码

此文件是数据源的枚举, 这里的枚举我们只配置里一个参数, 可以依据业务扩展. 本枚举的值代表数据源的名称, 是和配置文件里的配置对应上的

另外说明一下, NONE是用来代表默认数据源的, 是为了方便编程添加的, 不是必须的

DataSourceUtil

public class DataSourceUtil {

private static final ThreadLocal localDataSource = new ThreadLocal<>();

private DataSourceUtil(){

}

public static DataSourceType get() {

return localDataSource.get();

}

public static void set(DataSourceType type){

localDataSource.set(type);

}

public static void remove() {

localDataSource.remove();

}

}

复制代码

数据源切换工具类, 这里的核心是ThreadLocal<DataSourceType>变量, ThreadLocal以前有过文档分析, 主要是用来维护线程内部变量的, 其中:

  • get()方法用来获取数据源

  • set()方法用来设置数据源

  • remove()用来清除数据源

MybatisConfig*

@Configuration

@MapperScan(“jin.panpan.database.dao”)

public class MybatisConfig {

//默认数据源

@Primary

@Bean(“db1”)

@ConfigurationProperties(prefix = “spring.datasource.db1”)

public DataSource dataSource1(){

return DataSourceBuilder.create().build();

}

@Bean(“db2”)

@ConfigurationProperties(prefix = “spring.datasource.db2”)

public DataSource dataSource2(){

return DataSourceBuilder.create().build();

}

//动态数据源选择

@Bean

public DynamicDataSource dynamicDataSource(@Qualifier(“db1”) DataSource db1,

@Qualifier(“db2”) DataSource db2){

Map<Object, Object> map = new HashMap<>();

//此处的key 要和DynamicDataSource类的determineCurrentLookupKey方法返回值一致

map.put(DataSourceType.DB1.getDatabase(), db1);

map.put(DataSourceType.DB2.getDatabase(), db2);

DynamicDataSource dynamicDataSource = new DynamicDataSource();

dynamicDataSource.setTargetDataSources(map);

//设置默认数据库, 选择的数据库Bean注入时要带@Primary注释

dynamicDataSource.setDefaultTargetDataSource(db1);

return dynamicDataSource;

}

//会话工厂配置

@Bean

public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {

SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();

factoryBean.setDataSource(dynamicDataSource);

Resource[] resources = new PathMatchingResourcePatternResolver()

.getResources(“classpath:mappers/*xml”);

factoryBean.setMapperLocations(resources);

return factoryBean.getObject();

}

//事务管理配置

@Bean

public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource){

return new DataSourceTransactionManager(dynamicDataSource);

}

}

复制代码

本类主要用来配置和注入mybatis相关配置bean, 主要有下面几步:

  • 自动扫描mapper接口配置

@MapperScan(“jin.panpan.database.dao”)

一般常规配置, 如果不配置多数据源, 一般是在入口类上注解

  • 数据源注入

@ConfigurationProperties 导入配置文件里的配置

@Bean 指定数据源名称

@Primary 标记默认数据源

  • 数据源动态选择Bean注入

加载多个数据源, 如果需要的话, 指定默认数据源

需要注意数据源容器Map的key要和DataSourceType里的字段值一致, 否则无法切换

  • 会话工厂Bean配置

单数据源时, 一般无需手动配置; 多数据源时, 需要手动指定会话工厂, 但是配置是模式化的

  • 事务管理Bean配置

事务管理的配置也是模式化的, 一般无特殊处理之处

DynamicDataSource*

public class DynamicDataSource extends AbstractRoutingDataSource {

private static final Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

@Override

protected Object determineCurrentLookupKey() {

String database = DataSourceUtil.get() == null ? null : DataSourceUtil.get().getDatabase();

logger.info(“DynamicDataSource, 动态数据源返回={}”, database);

return database;

}

}

复制代码

此类其实是动态路由数据源的核心类, 扩展AbstractRoutingDataSource类, 重写determineCurrentLookupKey方法, determineCurrentLookupKey方法的返回值就是动态数据源, 返回值需要和配置文件及MybatisConfig里的一一对应.

DataSource和DataSourceAspect*

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@Documented

public @interface DataSource {

DataSourceType value() default DataSourceType.NONE;

}

复制代码

DataSource是一个方法注解, 用来作为数据源切换切入点, 此处可以使用类注解或者直接正则织入想监控的点

DataSourceAspect是注解的实现, 是核心实现

@Aspect

@Component

public class DataSourceAspect {

private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

@Pointcut(“@annotation(jin.panpan.database.dynamic.datasource.annotate.DataSource)”)

public void pointCut() {

}

@SneakyThrows

@Around(“pointCut()”)

public Object around(ProceedingJoinPoint pjp) {

//数据源

DataSourceType dataSourceType = null;

//方法对象

MethodSignature signature = (MethodSignature) pjp.getSignature();

Method method = signature.getMethod();

//注释

DataSource dynamicDataSource = method.getAnnotation(DataSource.class);

String path = null;

//注释中指定数据源, 则使用数据库中的数据源

if(dynamicDataSource.value()!=null && dynamicDataSource.value() != DataSourceType.NONE){

dataSourceType = dynamicDataSource.value();

}

//否则从请求路径中获取

if(dataSourceType == null){

HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

path = request.getRequestURL().toString();

//TODO 待优化 需截取域名进行检查

if(path.contains(DataSourceType.DB1.getDatabase())){

dataSourceType = DataSourceType.DB1;

}

if(path.contains(DataSourceType.DB2.getDatabase())){

dataSourceType = DataSourceType.DB2;

}

}

logger.info(“DataSource, 方法={}, 数据源={}, 路径={}, 注释自带数据源={}”,

method.getName(), dataSourceType==null ? null : dataSourceType.getDatabase(),

path, dynamicDataSource.value());

if(dataSourceType == null){

throw new Exception(“非法数据源”);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后:学习总结——MyBtis知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。下方即为我手绘的MyBtis知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的MyBtis知识脑图原件(包括上方的面试解析xmind文档)

image

除此之外,前文所提及的Alibaba珍藏版mybatis手写文档以及一本小小的MyBatis源码分析文档——《MyBatis源码分析》等等相关的学习笔记文档,也皆可分享给认可的朋友!

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
=“img” style=“zoom: 33%;” />

最后:学习总结——MyBtis知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。下方即为我手绘的MyBtis知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的MyBtis知识脑图原件(包括上方的面试解析xmind文档)

[外链图片转存中…(img-gAYdSixH-1712204577030)]

除此之外,前文所提及的Alibaba珍藏版mybatis手写文档以及一本小小的MyBatis源码分析文档——《MyBatis源码分析》等等相关的学习笔记文档,也皆可分享给认可的朋友!

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值