业务系统复杂程度增加,为了解决数据库I/O瓶颈,很自然会进行拆库拆表分服务来应对。这就会出现一个系统中可能会访问多处数据库,需要配置多个数据源。

第一种场景:项目服务从其它多处数据库取基础数据进行业务处理,因此各库之间不会出现重表等情况。

第二种场景:为了减轻写入压力进行读写分库,读走从库,写为主库。此种表名等信息皆为一致。

第三种场景:以上两种皆有。对于某些业务需要大数据量的汇总统计,希望不影响正常业务必须走从库(表信息一致),某些配置信息不存在读写压力,出现不分库(表信息不一致)

项目源代码:

https://github.com/zzsong/springboot-multiple-datasource.git

有三个目录:

one:
直接使用多@Bean配置,@MapperScan来路径区分读何库 two:
使用注解的方式来标识走何dataSource,AOP拦截注入动态数据源 third:
使用spring的Bean命名策略进行区分数据来源

项目技术选型: springBoot2.2.5 + mybatis + druid + mysql

先看主要的pom包

        <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>

application.yml

spring:
datasource:
druid:
core:
url: jdbc:mysql:///kc_core?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
schedule:
url: jdbc:mysql:///kc_schedule?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource

mysql新版本必须带有serverTimezone,不然会报连接异常。

第一种:通过@MapperScans 扫描匹配相关的数据源

@Configuration
@MapperScans({
@MapperScan(basePackages = "com.zss.one.mapper.core", sqlSessionTemplateRef = "coreSqlSessionTemplate",sqlSessionFactoryRef = "coreSqlSessionFactory"),
@MapperScan(basePackages = "com.zss.one.mapper.schedule", sqlSessionTemplateRef = "scheduleSqlSessionTemplate",sqlSessionFactoryRef = "scheduleSqlSessionFactory")
})
public class MybatisOneConfig { @Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.core")
public DataSource coreDataSource(){
return DruidDataSourceBuilder.create().build();
} @Bean
public SqlSessionFactory coreSqlSessionFactory(@Qualifier("coreDataSource") DataSource coreDataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(coreDataSource);
sessionFactory.getObject().getConfiguration().setJdbcTypeForNull(null);
sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return sessionFactory.getObject();
} @Bean
public SqlSessionTemplate coreSqlSessionTemplate(@Qualifier("coreSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
} //======schedule========
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.schedule")
public DataSource scheduleDataSource(){
return DruidDataSourceBuilder.create().build();
} @Bean
public SqlSessionFactory scheduleSqlSessionFactory(@Qualifier("scheduleDataSource") DataSource coreDataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(coreDataSource);
sessionFactory.getObject().getConfiguration().setJdbcTypeForNull(null);
sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return sessionFactory.getObject();
} @Bean
public SqlSessionTemplate scheduleSqlSessionTemplate(@Qualifier("scheduleSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

第二种是动态数据源模式,通过AOP切入注解引导使用何数据源。用自定义注解@interface来标识方法走对应的数据源。

注意事项:类中的方法再调用带数据源的方法,不能被AOP切入
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String value();
}

extends spring的动态DataSource路由来匹配

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
protected Object determineCurrentLookupKey() {
return DataSourceContextRouting.getDataSourceName();
}
}
@Configuration
//@EnableConfigurationProperties(MybatisProperties.class)//不要使用此公共配置,Configuration会破坏相关dataSource的配置
@MapperScan("com.zss.two.mapper")
public class MybatisConfig { @Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.core")
public DataSource coreDataSource() {
return DruidDataSourceBuilder.create().build();
} @Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.schedule")
public DataSource scheduleDataSource() {
return DruidDataSourceBuilder.create().build();
} @Autowired
@Qualifier("coreDataSource")
private DataSource coreDataSource; @Autowired
@Qualifier("scheduleDataSource")
private DataSource scheduleDataSource; @Bean
public DynamicDataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceConstants.CORE_DATA_SOURCE, coreDataSource);
targetDataSources.put(DataSourceConstants.SCHEDULE_DATA_SOURCE, scheduleDataSource); DynamicDataSource dataSource = new DynamicDataSource(); //设置数据源映射
dataSource.setTargetDataSources(targetDataSources);
//// 设置默认数据源,当无法映射到数据源时会使用默认数据源
dataSource.setDefaultTargetDataSource(coreDataSource);
dataSource.afterPropertiesSet();
return dataSource;
}
/**
* 根据数据源创建SqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.getObject().getConfiguration().setJdbcTypeForNull(null);
sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return sessionFactory.getObject();
} @Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}

第三种,自定义Bean命名策略,按beanName进行自动匹配使用数据源

@Component
public class CoreBeanNameGenerator implements BeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return "core"+ ClassUtils.getShortName(definition.getBeanClassName());
}
} @Component
public class ScheduleBeanNameGenerator implements BeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return "schedule"+ ClassUtils.getShortName(definition.getBeanClassName());
}
}

使用mybatis MapperScannerConfigurer自动扫描,将Mapper接口生成注入到spring

    @Bean
public MapperScannerConfigurer coreMapperScannerConfig(CoreBeanNameGenerator coreBeanNameGenerator){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setNameGenerator(coreBeanNameGenerator);
configurer.setBasePackage("com.zss.third.mapper.core,com.zss.third.mapper.order");
configurer.setSqlSessionFactoryBeanName("coreSqlSessionFactory");
configurer.setSqlSessionTemplateBeanName("coreSqlSessionTemplate");
return configurer;
} @Bean
public MapperScannerConfigurer scheduleMapperScannerConfig(ScheduleBeanNameGenerator scheduleBeanNameGenerator){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setNameGenerator(scheduleBeanNameGenerator);
configurer.setBasePackage("com.zss.third.mapper.schedule,com.zss.third.mapper.order");
configurer.setSqlSessionFactoryBeanName("scheduleSqlSessionFactory");
configurer.setSqlSessionTemplateBeanName("scheduleSqlSessionTemplate");
return configurer;
}

到此,三种多数据源匹配主要点介绍完,详细直接下载github项目。 在resources/db含有相关测试表及数据脚本。

springboot2 + mybatis 多种方式实现多数据配置的更多相关文章

  1. Spring实现Ioc的多种方式--控制反转、依赖注入、xml配置的方式实现IoC、对象作用域

    Spring实现Ioc的多种方式 一.IoC基础 1.1.概念: 1.IoC 控制反转(Inversion of Control) IoC是一种设计思想. 2.DI 依赖注入 依赖注入是实现IoC的一 ...

  2. Django 缓存配置的多种方式

    django 的缓存配置有多种方式,主要包含以下几种: 1.开发调试模式 2.内存模式 3.使用文件 4.直接使用数据库 5.使用redis或者memcache 这里主要是记录一下那些不常用,但是在微 ...

  3. Spring Boot 入门系列(二十三)整合Mybatis,实现多数据源配置!

    d之前介绍了Spring Boot 整合mybatis 使用注解方式配置的方式实现增删改查以及一些复杂自定义的sql 语句 .想必大家对spring boot 项目中,如何使用mybatis 有了一定 ...

  4. idea打包jar的多种方式

    这里总结出用IDEA打包jar包的多种方式,以后的项目打包Jar包可以参考如下形式: 用IDEA自带的打包形式 用Maven插件maven-shade-plugin打包 用Maven插件maven-a ...

  5. MySQL JDBC/MyBatis Stream方式读取SELECT超大结果集

    情景: 遍历并处理一个大表中的所有数据, 这个表中的数据可能会是千万条或者上亿条, 很多人可能会说用分页limit……但需求本身一次性遍历更加方便, 且Oracle/DB2都有方便的游标机制. 对DB ...

  6. Spring学习总结(一)——Spring实现IoC的多种方式

    控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法.没有IoC的程序中我们使用面向对象编程对象的创 ...

  7. java 获取classpath下文件多种方式

    java 获取classpath下文件多种方式 一:properties下配置 在resources下定义server.properties register.jks.path=classpath\: ...

  8. myBatis 基础测试 表关联关系配置 集合 测试

    myBatis 基础测试 表关联关系配置 集合 测试 测试myelipse项目源码 sql 下载 http://download.csdn.net/detail/liangrui1988/599388 ...

  9. Spring实现IoC的多种方式

    目录 一.使用XML配置的方式实现IOC 二.使用Spring注解配置IOC 三.自动装配 四.零配置实现IOC 五.示例下载 控制反转IoC(Inversion of Control),是一种设计思 ...

随机推荐

  1. LeetCode 232题用栈实现队列(Implement Queue using Stacks) Java语言求解

    题目链接 https://leetcode-cn.com/problems/implement-queue-using-stacks/ 题目描述 使用栈实现队列的下列操作: push(x) -- 将一 ...

  2. Java入门教程九(封装继承多态)

    封装 封装就是将对象的属性和方法相结合,通过方法将对象的属性和实现细节保护起来,实现对象的属性隐藏.做法就是:修改属性的可见性来限制对属性的访问,并为每个属性创建一对取值(getter)方法和赋值(s ...

  3. javascript设计模式--策略模式

    javascript策略模式总结 1.什么是策略模式? 策略模式的定义是:定义一系列的算法,把他们独立封装起来,并且可以相互替换. 例如我们需要写一段代码来计算员工的奖金.当绩效为a时,奖金为工资的5 ...

  4. Spring Cloud Feign 优雅的服务调用

    Fegin 是由NetFlix开发的声明式.模板化HTTP客户端,可用于SpringCloud 的服务调用.提供了一套更优雅.便捷的HTTP调用API,并且SpringCloud整合了Fegin.Eu ...

  5. 峰哥说技术:09-Spring Boot整合JSP视图

    Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 09  峰哥说技术:Spring Boot整合JSP视图 一般来说我们很少推荐大家在Spring boot ...

  6. docker 搭建本地私有仓库

    1.使用registry镜像创建私有仓库 安装docker后,可以通过官方提供的 registry 镜像来简单搭建一套本地私有仓库环境: docker run -d -p : registry: 这将 ...

  7. MyBatis 源码分析-项目总览

    MyBatis 源码分析-项目总览 1.概述 本文主要大致介绍一下MyBatis的项目结构.引用参考资料<MyBatis技术内幕> 此外,https://mybatis.org/mybat ...

  8. Json转化的三种方式

    1. Gson 1.添加依赖 <dependency> <groupId>com.google.code.gson</groupId> <artifactId ...

  9. Html5 部分帮助文档 未完待续

     W3cSchoolH5帮助文档 Video属性 视频播放效果 Video标签 src视频得目录 controls属性提供添加 播放 和音量控件 当然呢 不设置宽和高得话 视频会很大 Video还可以 ...

  10. .NET CORE之Authentication

    这篇文章以实现一个Basic认证来了解下在 .NET CORE 下面如何去实现认证. 首先可以肯定的是认证实现是基于 Middlerware 管道实现的,官方源码地址:https://github.c ...