springboot mybatis多数据源的两种整合方法

发布时间:2025-01-14 18:57

它能收集并整合各种来源的数据 #生活技巧# #领导力技巧# #决策支持系统#

一个项目使用多个数据库(无论是主从复制--读写分离还是分布式数据库结构)的重要性变得越来越明显,整合的多数据源有两种方式:分包和aop。

分包

以分包的方式来区分不同的数据源,也就是不同的包,连接不同的数据库。

1、application的数据源配置

##数据源1

##driverClassName driver-class-name

spring.datasource.test1.driver-class-name: com.mysql.jdbc.Driver

spring.datasource.test1.jdbc-url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true

spring.datasource.test1.username: root

spring.datasource.test1.password: root

#数据源2

spring.datasource.test2.driver-class-name: com.mysql.jdbc.Driver

spring.datasource.test2.jdbc-url: jdbc:mysql://127.0.0.1:3306/springboot1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true

spring.datasource.test2.username: root

spring.datasource.test2.password: root

2、数据源配置类

DataSource1Config.java

@Configuration

@MapperScan(basePackages = "com.jessDl.dataSource1",

sqlSessionTemplateRef = "test1SqlSessionTemplate")

public class DataSource1Config {

@Bean(name = "test1DataSource")

@ConfigurationProperties(prefix = "spring.datasource.test1")

public DataSource testDataSource() {

return DataSourceBuilder.create().build();

}

@Bean(name = "test1SqlSessionFactory")

public SqlSessionFactory testSqlSessionFactory(

@Qualifier("test1DataSource") DataSource dataSource) throws Exception {

SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

bean.setDataSource(dataSource);

getResources("classpath:mybatis/mapper/test1/*.xml"));

return bean.getObject();

}

@Bean(name = "test1TransactionManager")

public DataSourceTransactionManager testTransactionManager(

@Qualifier("test1DataSource") DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

@Bean(name = "test1SqlSessionTemplate")

public SqlSessionTemplate testSqlSessionTemplate(

@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {

return new SqlSessionTemplate(sqlSessionFactory);

}

}

这里我们要对mybatis sqlSession有一些认识和理解,mybatis进行持久化时有几个重要的类:

(1)SqlSessionFactoryBuilder: build方法创建SqlSessionFactory实例。

(2)SqlSessionFactory: 创建SqlSession实例的工厂。

(3)SqlSession: 用于持久化操作的对象,类似于jdbc中的Connection。

(4)SqlSessionTemplate:  持久化层访问模板化的工具,线程安全,可通过构造参数或依赖注入。

一层层的注入,先创建DataSource,再创建SqlSessionFactory,再创建事务,最后包装到SqlSessionTemplate中。其中需要制定分库的mapper文件地址,以及分库dao层

DataSource2Config.java

@Configuration

@MapperScan(basePackages = "com.jessDl.dataSource2", sqlSessionTemplateRef = "test2SqlSessionTemplate")

public class DataSource2Config {

@Bean(name = "test2DataSource")

@ConfigurationProperties(prefix = "spring.datasource.test2")

public DataSource testDataSource() {

return DataSourceBuilder.create().build();

}

@Bean(name = "test2SqlSessionFactory")

public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception {

SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

bean.setDataSource(dataSource);

return bean.getObject();

}

@Bean(name = "test2TransactionManager")

public DataSourceTransactionManager testTransactionManager(@Qualifier("test2DataSource") DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

@Bean(name = "test2SqlSessionTemplate")

public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {

return new SqlSessionTemplate(sqlSessionFactory);

}

}

dataSource1操作数据源1,dataSource2操作数据源2. dao喜忧参半和xml需要按照库来分在不同的目录。

aop方式

1、AbstractRoutingDataSource

实现数据源切换的功能就是自定义一个类扩展AbstractRoutingDataSource抽象类,而AbstractRoutingDataSource又继承于AbstractDataSource,AbstractDataSource实现了统一的DataSource接口。

public class DynamicDataSource extends AbstractRoutingDataSource{

@Override

protected Object determineCurrentLookupKey() {

return DataSourceContextHolder.getDataSourceType();

}

}

这里我们编写一个根据当前线程来选择数据源,然后通过AOP拦截特定的注解。

配置的多个数据源会放在AbstractRoutingDataSource的targetDataSources和defaultTargetDataSource中。

AbstractRoutingDataSource的getConnection()的方法的时候,先调用determinTargetDataSource()方法返回DataSource在进行getConnection()

protected DataSource determineTargetDataSource() {

Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");

Object lookupKey = determineCurrentLookupKey();

DataSource dataSource = this.resolvedDataSources.get(lookupKey);

if (dataSource == null && (this.lenientFallback || lookupKey == null)) {

dataSource = this.resolvedDefaultDataSource;

}

if (dataSource == null) {

throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");

}

return dataSource;

}

很简单就可以看到,我们通过自己实现的determineCurrentLookupKey()方法返回了lookupKey,根据配置的key就获取到对应的数据源达到切换的功能。

2、yml配置

spring:

datasource:

druid:

db1:

url: jdbc:mysql://localhost:3306/eboot

username: root

password: root

driver-class-name: com.mysql.jdbc.Driver

initialSize: 5

minIdle: 5

maxActive: 20

db2:

url: jdbc:oracle:thin:@192.168.136.222:ORCL

username: sa

password: sa123456

driver-class-name: oracle.jdbc.OracleDriver

initialSize: 5

minIdle: 5

maxActive: 20

db3:

url: jdbc:oracle:thin:@192.168.136.223:ORCL

username: sb

password: sb123456

driver-class-name: oracle.jdbc.OracleDriver

initialSize: 5

minIdle: 5

maxActive: 20

3、pom依赖

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>druid-spring-boot-starter</artifactId>

<version>1.1.9</version>

</dependency>

4、把数据源放入DruidDataSource中

@EnableTransactionManagement

@Configuration

public class DataSourceConfig {

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

@Bean(name="db1")

@ConfigurationProperties(prefix = "spring.datasource.druid.db1")

public DataSource db1(){

return DruidDataSourceBuilder.create().build();

}

@Bean(name="db2")

@ConfigurationProperties(prefix = "spring.datasource.druid.db2")

public DataSource db2(){

return DruidDataSourceBuilder.create().build();

}

@Bean

@Primary

public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,

@Qualifier("db2") DataSource db2){

DynamicDataSource dynamicDataSource = new DynamicDataSource();

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

targetDataSources.put(DataSourceType.PG1.getName(),db1);

targetDataSources.put(DataSourceType.PG2.getName(),db2);

dynamicDataSource.setTargetDataSources(targetDataSources);

dynamicDataSource.setDefaultTargetDataSource(db1);

return dynamicDataSource;

}

}

5、为了规范,DataSourceType枚举类

public enum DataSourceType {

PG1("pg1"),

PG2("pg2");

private String name;

DataSourceType(String name){

this.name = name;

}

public String getName(){

return name;

}

public void setName(String name){

this.name = name;

}

}

6、动态数据决策类

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey(){

return BaseContextHandler.get(EvaConstants.DATA_SOURCE);

}

}

7.ThreadLocal类

public class BaseContextHandler {

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

public static ThreadLocal<Map<String,Object>> threadLocal = new ThreadLocal<>();

public static void set(String key,Object value){

Map<String,Object> map = threadLocal.get();

if(map==null){

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

threadLocal.set(map);

}

map.put(key,value);

}

public static Object get(String key){

Map<String,Object> map = threadLocal.get();

if(map==null){

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

threadLocal.set(map);

}

return map.get(key);

}

public static void remove(){

threadLocal.remove();

}

}

8、AOP

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface TargetDataSource {

DataSourceType value() default DataSourceType.PG1;

}

@Aspect

@Order(2)

@Component

public class DataSourceAspect {

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

@Before("@annotation(targetDataSource)")

public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource){

DataSourceType dbType = targetDataSource.value();

if(dbType.equals(DataSourceType.PG1)){

BaseContextHandler.set(EvaConstants.DATA_SOURCE,DataSourceType.PG1.getName());

}else{

BaseContextHandler.set(EvaConstants.DATA_SOURCE,DataSourceType.PG2.getName());

}

}

@After("@annotation(targetDataSource)")

public void clearDataSource(JoinPoint joinPoint,TargetDataSource targetDataSource){

BaseContextHandler.remove();

}

}

这样在dao层只需要这样

@TargetDataSource(value= DataSourceType.PG2)

int getSeq(@Param("seqName")String seqName);

网址:springboot mybatis多数据源的两种整合方法 https://www.yuejiaxmz.com/news/view/714901

相关内容

【SpringBoot】整合Mybatis
【附源码】计算机毕业设计健康食谱推荐分享系统(java+springboot+mysql+mybatis+论文)
Springboot减重系统g0d5s(程序+源码+数据库+调试部署+开发环境)
Mybatis
【含文档】基于Springboot+Vue的二手书籍交易系统(含源码+数据库+lw)
Springboot+ssm(Spring+SpringMVC+MyBatis)旧物置换网站
Springboot健身会馆预约管理系统o14kl(程序+源码+数据库+调试部署+开发环境)
Springboot家居产品的进销存系统dgo68(程序+源码+数据库+调试部署+开发环境)
Springboot家具商城系统h4q2o(程序+源码+数据库+调试部署+开发环境)
Springboot健康管理系统1ii1u(程序+源码+数据库+调试部署+开发环境)

随便看看