在项目开发中,有一些场景需要同时使用多个数据库,并且需要能够根据需求能够动态切换,下面介绍一种基于注解+aop的方式。


  • 动态多数据源实现

    • Spring boot启动类(Application)
    • 数据库配置文件(dynamic-multi-db.yml)
    • 数据源配置类(DataSourceConfig)
    • 数据源上下文(DataSourceContextHolder)
    • 动态数据源(DynamicDataSource)
    • 数据源切换注解(DS)
    • 数据源切换切面(DynamicDataSourceAspect)
  • 动态多数据源测试
    • 建表语句
    • 数据库实体(person)
    • 数据访问对象(PersonDao)
    • Service层接口(PersonService )
    • Service接口实现(PersonServiceImpl )
    • Controller(PersonController )
    • 测试结果

动态多数据源实现

Spring boot启动类(Application)

首先要将spring boot自带的DataSourceAutoConfiguration禁掉,因为它会读取application.properties文件的spring.datasource.*属性并自动配置单数据源。在@SpringBootApplication注解中添加exclude属性即可:

/*** springboot启动类* 使用exclude = {DataSourceAutoConfiguration.class}* 禁用springboot默认加载的application.properties单数据源配置*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableTransactionManagement
public class Application {public static void main(String[] args) {SpringApplication app = new SpringApplication(Application.class);app.setBannerMode(Banner.Mode.OFF);app.run(args);}
}

数据库配置文件(dynamic-multi-db.yml)

配置数据源,其中前缀为“spring.datasource”的为默认数据源,前缀为“spring.datasource.provider”的为provider数据源,前缀为“spring.datasource.consumer”的为consumer数据源。

spring:datasource:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/default_db?useUnicode=true&noDatetimeStringSync=true&characterEncoding=utf8username: usernamepassword: passwordprovider:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/provider_db?useUnicode=true&noDatetimeStringSync=true&characterEncoding=utf8username: usernamepassword: passwordconsumer:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/consumer_db?useUnicode=true&noDatetimeStringSync=true&characterEncoding=utf8username: usernamepassword: password

数据源配置类(DataSourceConfig)

由于我们禁掉了Spring boot的自动数据源配置,因些需要手动将数据源创建出来,通过读取application.properties(dynamic-multi-db.yml)文件生成三个数据源(dataSourceDefault、dataSourceProvider、dataSourceConsumer),并使用这三个数据源动态构建DataSource。

/*** Mybatis多数据源配置类*/
@Configuration
@MapperScan("com.wind.test.dao.mybatis")
public class DataSourceConfig {/*** 默认数据源** @return*/@Bean(name = "dataSourceDefault")@ConfigurationProperties(prefix = "spring.datasource")public DataSource dataSourceDefault() {return DataSourceBuilder.create().build();}/*** 来源库** @return*/@Bean(name = "dataSourceProvider")@ConfigurationProperties(prefix = "spring.datasource.provider")public DataSource dataSourceProvider() {return DataSourceBuilder.create().build();}/*** 目标库** @return*/@Bean(name = "dataSourceConsumer")@ConfigurationProperties(prefix = "spring.datasource.consumer")public DataSource dataSourceConsumer() {return DataSourceBuilder.create().build();}/*** 动态数据源: 通过AOP在不同数据源之间动态切换* 将数据库实例写入到targetDataSources属性中,并且使用defaultTargetDataSource属性设置默认数据源。* @Primary 注解用于标识默认使用的 DataSource Bean,并注入到SqlSessionFactory的dataSource属性中去。* * @return*/@Primary@Bean(name = "dynamicDataSource")public DataSource dynamicDataSource() {DynamicDataSource dynamicDataSource = new DynamicDataSource();// 默认数据源dynamicDataSource.setDefaultTargetDataSource(dataSourceDefault());// 配置多数据源Map<Object, Object> dsMap = new HashMap();dsMap.put("dataSourceDefault", dataSourceDefault());dsMap.put("dataSourceProvider", dataSourceProvider());dsMap.put("dataSourceConsumer", dataSourceConsumer());dynamicDataSource.setTargetDataSources(dsMap);return dynamicDataSource;}/*** 配置@Transactional注解事物* 使用dynamicDataSource作为transactionManager的入参来构造DataSourceTransactionManager* * @return*/@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dynamicDataSource());}
}

数据源上下文(DataSourceContextHolder)

使用ThreadLocal提供一个线程安全的容器,存储创建出来的DataSource Bean的示例名

/*** 数据源上下文*/
public class DataSourceContextHolder {/*** 默认数据源*/public static final String DEFAULT_DS = "dataSourceDefault";/*** 使用ThreadLocal存储数据源*/private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();/*** 设置数据源** @param dbType*/public static void setDB(String dbType) {contextHolder.set(dbType);}/*** 获取数据源** @return*/public static String getDB() {return (contextHolder.get());}/*** 清除数据源*/public static void clearDB() {contextHolder.remove();}
}

动态数据源(DynamicDataSource)

DynamicDataSource继承AbstractRoutingDataSource并重写其中的方法determineCurrentLookupKey(),在该方法中使用DatabaseContextHolder获取当前线程指定的数据源。

/*** 动态数据源*/
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDB();}
}

数据源切换注解(DS)

定义一个@DS注解类,在运行时动态切换数据源。

/*** 数据源切换注解*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DS {public static final String dataSourceProvider = "dataSourceProvider";public static final String dataSourceConsumer = "dataSourceConsumer";String value() default "dataSourceDefault";
}

数据源切换切面(DynamicDataSourceAspect)

使用AOP解析@DS注解的方法,实现动态数据源切换。

/*** 自定义注解@DS + AOP的方式实现数据源动态切换。*/
@Aspect
@Component
public class DynamicDataSourceAspect {@Before("@annotation(DS)")public void beforeSwitchDS(JoinPoint point) {//获得当前访问的classClass<?> className = point.getTarget().getClass();//获得访问的方法名String methodName = point.getSignature().getName();//得到方法的参数的类型Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();String dataSource = DataSourceContextHolder.DEFAULT_DS;try {// 得到访问的方法对象Method method = className.getMethod(methodName, argClass);// 判断是否存在@DS注解if (method.isAnnotationPresent(DS.class)) {DS annotation = method.getAnnotation(DS.class);// 取出注解中的数据源名dataSource = annotation.value();}} catch (Exception e) {e.printStackTrace();}// 切换数据源DataSourceContextHolder.setDB(dataSource);}@After("@annotation(DS)")public void afterSwitchDS(JoinPoint point) {DataSourceContextHolder.clearDB();}
}

动态多数据源测试

测试方法:在provider库中查询数据插入到consumer库中,如果插入成功则动态多数据源配置成功。

建表语句

CREATE TABLE `person` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`age` int(11) DEFAULT NULL,`address` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4;-- 下面语句provider库执行,consumer库不执行
-- insert into person (name,age,address) values ('dynamic',124,'多数据源镇动态村');

数据库实体(person)

/*** 数据库实体-动态多数据源测试*/
@Setter
@Getter
@TableName("person")
public class PersonEntity extends BaseMybatisEntity<PersonEntity> {private String name;private Integer age;private String address;}

数据访问对象(PersonDao)

/*** DAO - 多数据源测试*/
public interface PersonDao extends MybatisMapper<PersonEntity> {}

Service层接口(PersonService )

/*** Service - 动态多数据源测试*/
public interface PersonService extends BaseMybatisService<PersonEntity> {/*** 查询** @param name* @return*/PersonEntity findOne(String name);/*** 新增** @param personEntity* @return*/@Overrideboolean insert(PersonEntity personEntity);
}

Service接口实现(PersonServiceImpl )

/*** ServiceImpl - 动态多数据源测试*/
@Service
public class PersonServiceImpl extends BaseMybatisServiceImpl<PersonDao, PersonEntity> implements PersonService {/*** 从数据源获取数据** @param name* @return*/@Override@DS(DS.dataSourceProvider)public PersonEntity findOne(String name) {Wrapper<PersonEntity> wrapper = Condition.create().eq("name", name);PersonEntity personEntity = super.selectOne(wrapper);return personEntity;}/*** 将数据插入目标数据库** @param personEntity* @return*/@Override@DS(DS.dataSourceConsumer)public boolean insert(PersonEntity personEntity) {return super.insert(personEntity);}
}

Controller(PersonController )

/*** Controller - 动态多数据源测试*/
@RestController
@RequestMapping()
public class PersonController extends BaseController {@AutowiredPersonService personService;/*** 动态多数据源测试* 从provider数据库读取数据插入到consumer数据库** @param personDto* @return*/@PostMapping("/v1/person/{name}")public boolean add(@PathVariable String name) {logger.info("Request-URI: Post/v1/person/{}", name);PersonEntity personEntity = personService.findOne(name);return personService.insert(personEntity);}
}

测试结果

请求之后可以看到consumer数据库中已经插入了从provider库中查询出来的数据

参考文献
https://blog.csdn.net/neosmith/article/details/61202084
https://blog.csdn.net/xiaosheng_papa/article/details/80218006
https://www.cnblogs.com/java-zhao/p/5413845.html

Spring boot + Mybatis动态多数据源实现相关推荐

  1. Spring Boot + Mybatis 实现动态数据源

    动态数据源 在很多具体应用场景的时候,我们需要用到动态数据源的情况,比如多租户的场景,系统登录时需要根据用户信息切换到用户对应的数据库.又比如业务A要访问A数据库,业务B要访问B数据库等,都可以使用动 ...

  2. Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置

    Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置 前言: 1. 数据库准备: 2. 环境准备: 3.代码部分 4. 测试: 5.等等 6.配合注解实现 7 .测试 ...

  3. java多个数据库数据进行访问_通过Spring Boot配置动态数据源访问多个数据库的实现代码...

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中 ...

  4. mysql 多数据源访问_通过Spring Boot配置动态数据源访问多个数据库的实现代码

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中 ...

  5. spring boot+Mybatis+mysql+atomikos+jta实现多数据源分布式事务

    spring boot+Mybatis+mysql+atomikos+jta实现多数据源分布式事务 1.导入相关依赖 2.配置相关application.properties 3.创建配置文件 4.创 ...

  6. Spring Boot使用动态数据源

    文章目录 前言 一.什么是动态数据源 二.动态数据源实现 1.实现原理 2.实现过程 前言 有这样一个场景,现在要开发一个数据API功能,用户自己编写数据源脚本,在界面任意选择一个数据源,可选择的数据 ...

  7. spring boot + mybatis + layui + shiro后台权限管理系统

    后台管理系统 版本更新 后续版本更新内容 链接入口: springboot + shiro之登录人数限制.登录判断重定向.session时间设置:https://blog.51cto.com/wyai ...

  8. 商城项目(一)使用Spring boot + Mybatis搭建

    Spring boot + Mybatis基础架构 环境搭建 mysql 8 mysql客户端连接工具 Valentina Studio springboot 版本:2.1.3.RELEASE Myb ...

  9. spring boot+mybatis整合

    LZ今天自己搭建了下Spring boot+Mybatis,比原来的Spring+SpringMVC+Mybatis简单好多.其实只用Spring boot也可以开发,但是对于多表多条件分页查询,Sp ...

最新文章

  1. LeetCode简单题之整数的各位积和之差
  2. 比特币核心概念及算法
  3. 如何理解delegate (委托)设计模式
  4. 【UML 建模】UML建模语言入门 -- 静态图详解 类图 对象图 包图 静态图建模实战
  5. qnx bsp 编译
  6. 【深度学习】围观特斯拉总监把玩MNIST
  7. ORACLE中数据类型
  8. java和网易我的世界有什么区别_网易我的世界手机版对比正版JAVA版我的世界有什么区别?...
  9. 跟小海一起看下雪——用HTML、CSS和JS实现简单的下雪特效
  10. 阿里云短信接口对接(java版)
  11. java spring security详解
  12. LeetCola_19_删除链表的倒数第N个节点_0723M
  13. photoshop制作gif动画
  14. K66芯片解锁/J-link报错的解决思路
  15. Python 如何画出漂亮的地图?
  16. python练习39:有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。
  17. 数据传输性能与安全不能兼顾?Rambus安全方案“动静”两相宜
  18. 《计算机寓言 - 信息时代的启示》【转载】
  19. 电子病历模板编辑器_这几个邮件模板网站,帮助提升工作效率
  20. 7-38 实验7_3_奇数偶数 (100 分)奇数偶数排序

热门文章

  1. 【2022】招商银行信用卡中心春招实习生技术岗A卷
  2. 项目管理探究之挣值管理常见计算
  3. Knapsack Problem
  4. ubuntu-眼睛卫视
  5. Google 文件系统
  6. matlab永磁同步电机验证,采用Matlab/Simulink软件实现永磁同步电动机控制系统的建模与仿真...
  7. 股票自选股基本函数大全-2
  8. [bugku]解密系列+杂项
  9. 物联网大数据平台TIZA STAR架构解析
  10. 了解 JS 压缩图片,这一篇就够了