SpringBoot2+Mybatis两个数据源实现 (二)

2024-04-05 07:18

本文主要是介绍SpringBoot2+Mybatis两个数据源实现 (二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前转过一篇《SpringBoot2+Mybatis多个数据源实现》,今天补充一个其他的解决方案(原理差不多),这里是使用mysql+sqlserver作为数据源,可以供大家参考一下。

一、依赖引入

首先引入必要的jar包,有省略,自行补充
pom.xml

<!--连接池 -->
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>3.2.0</version>
</dependency>
<!--mysql -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.31</version>
</dependency>
<!-- sqlserver-->
<dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>sqljdbc4</artifactId><version>4.0</version>
</dependency>
<!-- mybatis -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.0.0</version>
</dependency>
二、代码实现

先创建 DatabaseType,定义两个数据源的名称

public enum DatabaseType {mysqlDataSource,sqlServerDataSource
}

实现DatabaseContextHolder

public class DatabaseContextHolder {private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();public static void setDatabaseType(DatabaseType type) {contextHolder.set(type);}public static DatabaseType getDatabaseType() {return contextHolder.get();}
}

实现DynamicDataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DatabaseContextHolder.getDatabaseType();}
}

实现MyBatisConfig

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration // 该注解类似于spring配置文件
@MapperScan(basePackages = "com.xxx.dao")
public class MyBatisConfig {@Autowiredprivate Environment env;// 读取主数据源@Beanpublic DataSource mysqlDataSource(Environment env) {Map<String, Object> dsMap = new HashMap<>();dsMap.put("type", env.getProperty("spring.datasource.type"));dsMap.put("driver", env.getProperty("spring.datasource.driver-class-name"));dsMap.put("url", env.getProperty("spring.datasource.url"));dsMap.put("username", env.getProperty("spring.datasource.username"));dsMap.put("password", env.getProperty("spring.datasource.password"));return buildDataSource(dsMap);}// 读取从数据源@Beanpublic DataSource sqlServerDataSource(Environment env) {Map<String, Object> dsMap = new HashMap<>();dsMap.put("type", env.getProperty("slave.datasource.type"));dsMap.put("driver", env.getProperty("slave.datasource.driver-class-name"));dsMap.put("url", env.getProperty("slave.datasource.url"));dsMap.put("username", env.getProperty("slave.datasource.username"));dsMap.put("password", env.getProperty("slave.datasource.password"));return buildDataSource(dsMap);}/*** @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错* @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)*/@Bean@Primarypublic DynamicDataSource dataSource(@Qualifier("mysqlDataSource") DataSource mysqlDataSource,@Qualifier("sqlServerDataSource") DataSource sqlServerDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DatabaseType.mysqlDataSource, mysqlDataSource);targetDataSources.put(DatabaseType.sqlServerDataSource, sqlServerDataSource);DynamicDataSource dataSource = new DynamicDataSource();dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法dataSource.setDefaultTargetDataSource(mysqlDataSource);// 默认的datasource设return dataSource;}/*** 根据数据源创建SqlSessionFactory*/@Beanpublic SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {SqlSessionFactoryBean fb = new SqlSessionFactoryBean();fb.setDataSource(ds);// 指定数据源(这个必须有,否则报错)// 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加//fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定基包fb.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(env.getProperty("mybatis.config-location")));fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapper-locations")));return fb.getObject();}/*** 配置事务管理器*/@Beanpublic DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {return new DataSourceTransactionManager(dataSource);}/*** 创建DataSource* @param dataSourceMap* @return*/public DataSource buildDataSource(Map<String, Object> dataSourceMap) {try {Object type = dataSourceMap.get("type");Class<? extends DataSource> dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);String driverClassName = dataSourceMap.get("driver").toString();String url = dataSourceMap.get("url").toString();String username = dataSourceMap.get("username").toString();String password = dataSourceMap.get("password").toString();// 自定义DataSource配置DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url).username(username).password(password).type(dataSourceType);return factory.build();} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}
}
三、yml文件配置

application.yml

server:tomcat:uri-encoding: UTF-8max-threads: 1000min-spare-threads: 30port: 8888spring:profiles:active: dev#mybatis
mybatis:mapper-locations: classpath:mybatis/mappers/*.xmlconfig-location: classpath:mybatis/mybatis-config.xml

定义application-dev.yml

#mysql
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:33306/test1?useAffectedRows=true&characterEncoding=utf8username: rootpassword: roottype: com.zaxxer.hikari.HikariDataSourcehikari:connection-timeout: 30000idle-timeout: 600000max-lifetime: 1800000maximum-pool-size: 10#sqlserver
slave:datasource:driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriverurl: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=test2;username: sapassword: 123456type: com.zaxxer.hikari.HikariDataSourcehikari:connection-timeout: 30000idle-timeout: 600000max-lifetime: 1800000maximum-pool-size: 10
四、使用方式

建议在service实现类里面使用

public List<Demo> queryList(){//切换数据源DatabaseContextHolder.setDatabaseType(DatabaseType.sqlServerDataSource);Map<String,Object> map = new HashMap<>();return demoDao.queryList(map);
}public List<Demo> selectList(){//切换数据源DatabaseContextHolder.setDatabaseType(DatabaseType.mysqlDataSource);Map<String,Object> map = new HashMap<>();return demoDao.queryList(map);
}

20190709更新
之前hikari的配置未生效

hikari:connection-timeout: 30000idle-timeout: 600000max-lifetime: 1800000maximum-pool-size: 10

今天优化了一下MyBatisConfig,增加了配置Hikari dataSource的超时设置,详细看代码

package com.xxx.config;import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration // 该注解类似于spring配置文件
@MapperScan(basePackages = "com.xxx.dao")
public class MyBatisConfig {@Autowiredprivate Environment env;// 读取主数据源@Beanpublic DataSource mysqlDataSource(Environment env) {HikariConfig config = new HikariConfig();config.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));config.setJdbcUrl(env.getProperty("spring.datasource.url"));config.setUsername(env.getProperty("spring.datasource.username"));config.setPassword(env.getProperty("spring.datasource.password"));config.setConnectionTestQuery(env.getProperty("spring.datasource.ConnectionTestQuery"));config.setMaximumPoolSize(Integer.parseInt(env.getProperty("spring.datasource.hikari.maximum-pool-size")));config.setIdleTimeout(Integer.parseInt(env.getProperty("spring.datasource.hikari.idle-timeout")));config.setMaxLifetime(Integer.parseInt(env.getProperty("spring.datasource.hikari.max-lifetime")));config.setConnectionTimeout(Integer.parseInt(env.getProperty("spring.datasource.hikari.connection-timeout")));DataSource dataSource = new HikariDataSource(config);return dataSource;}// 读取从数据源@Beanpublic DataSource sqlServerDataSource(Environment env) {HikariConfig config = new HikariConfig();config.setDriverClassName(env.getProperty("slave.datasource.driver-class-name"));config.setJdbcUrl(env.getProperty("slave.datasource.url"));config.setUsername(env.getProperty("slave.datasource.username"));config.setPassword(env.getProperty("slave.datasource.password"));config.setConnectionTestQuery(env.getProperty("slave.datasource.ConnectionTestQuery"));config.setMaximumPoolSize(Integer.parseInt(env.getProperty("slave.datasource.hikari.maximum-pool-size")));config.setIdleTimeout(Integer.parseInt(env.getProperty("slave.datasource.hikari.idle-timeout")));config.setMaxLifetime(Integer.parseInt(env.getProperty("slave.datasource.hikari.max-lifetime")));config.setConnectionTimeout(Integer.parseInt(env.getProperty("slave.datasource.hikari.connection-timeout")));DataSource dataSource = new HikariDataSource(config);return dataSource;}/*** @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错* @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)*/@Bean@Primarypublic DynamicDataSource dataSource(@Qualifier("mysqlDataSource") DataSource mysqlDataSource,@Qualifier("sqlServerDataSource") DataSource sqlServerDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DatabaseType.mysqlDataSource, mysqlDataSource);targetDataSources.put(DatabaseType.sqlServerDataSource, sqlServerDataSource);DynamicDataSource dataSource = new DynamicDataSource();dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法dataSource.setDefaultTargetDataSource(mysqlDataSource);// 默认的datasource设return dataSource;}/*** 根据数据源创建SqlSessionFactory*/@Beanpublic SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {SqlSessionFactoryBean fb = new SqlSessionFactoryBean();fb.setDataSource(ds);// 指定数据源(这个必须有,否则报错)// 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加//fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定基包fb.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(env.getProperty("mybatis.config-location")));fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapper-locations")));//return fb.getObject();}/*** 配置事务管理器*/@Beanpublic DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {return new DataSourceTransactionManager(dataSource);}
}

这篇关于SpringBoot2+Mybatis两个数据源实现 (二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/877958

相关文章

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

Python使用pip工具实现包自动更新的多种方法

《Python使用pip工具实现包自动更新的多种方法》本文深入探讨了使用Python的pip工具实现包自动更新的各种方法和技术,我们将从基础概念开始,逐步介绍手动更新方法、自动化脚本编写、结合CI/C... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

在Linux中改变echo输出颜色的实现方法

《在Linux中改变echo输出颜色的实现方法》在Linux系统的命令行环境下,为了使输出信息更加清晰、突出,便于用户快速识别和区分不同类型的信息,常常需要改变echo命令的输出颜色,所以本文给大家介... 目python录在linux中改变echo输出颜色的方法技术背景实现步骤使用ANSI转义码使用tpu

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合