多数据源适配说明文档
一、背景说明
因业务拓展需要对接外部推送的业务数据,现有系统核心本地基础库采用 PostgreSQL 数据库(存储基础配置、核心元数据),新增的业务数据推送相关表部署在 MySQL 数据库(存储推送的业务明细数据)。为满足跨数据源的数据查询、整合需求,系统需适配 PostgreSQL + MySQL 双数据源架构,确保两类数据源独立管理、数据交互正常。
二、数据源配置说明
1. 核心配置文件(application.yml)
系统通过 application.yml 区分两个数据源的连接信息,关键配置如下:
spring:
# 多数据源配置
datasource:
# 主数据源:PostgreSQL(YFGASysDB)
postgres:
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5432/xxx
username: xxx
password: xxx
hikari:
maximum-pool-size: 50
minimum-idle: 5
idle-timeout: 30000
connection-timeout: 120000
# 次数据源:MySQL(warehouse_manager)
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
username: xxx
password: xxx
hikari:
maximum-pool-size: 20
minimum-idle: 2
idle-timeout: 30000
connection-timeout: 60000
# MyBatis基础配置(不变)
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
typeAliasesPackage: com.ss.emergency_systemctl.model
configuration:
call-setters-on-nulls: true
map-underscore-to-camel-case: true
mybatis-plus:
configuration:
type-handlers-package: com.ss.emergency_systemctl.config
# Swagger开关(不变)
swagger:
enable: true
# 日志配置(不变)
logging:
level:
root: info
com.njcky: debug
org.springframework: warn
2. 数据源核心配置类(DataSourceConfig.java)
通过 DataSourceConfig 类将配置文件中的连接信息转换为 Spring 可识别的 DataSource Bean,实现数据源的实例化与隔离:
- 主数据源(PostgreSQL):Bean 名称
postgresDataSource,标记@Primary避免默认数据源冲突; - 次数据源(MySQL):Bean 名称
mysqlDataSource,专用于业务数据推送相关操作; - 同时为两个数据源配置独立的事务管理器(
postgresTransactionManager/mysqlTransactionManager),确保事务隔离。
3. MyBatis 分库配置
为避免 SQL 执行与数据源不匹配,系统为两个数据源配置独立的 MyBatis 规则:
| 数据源 | MyBatis 配置类 | Mapper 接口包路径 | XML 文件路径 | 核心规则 |
|---|---|---|---|---|
| PostgreSQL | PostgresMyBatisConfig | com.ss.emergency_systemctl.mapper.postgres | classpath:mapper/postgres/*.xml | SQL 用 STRING_AGG 函数 |
| MySQL | MysqlMyBatisConfig | com.ss.emergency_systemctl.mapper.mysql | classpath:mapper/my |
三、核心实现方案
1. 数据查询隔离
- PostgreSQL 相关 Mapper 接口 / XML 仅操作本地基础库表,SQL 需兼容 PostgreSQL 语法
- MySQL 相关 Mapper 接口 / XML 仅操作业务数据推送表(如 表一/
表二/表三),SQL 兼容 - Service 层通过注入对应包下的 Mapper 实现分库查询(如注入
mysql包下的 )
MysqlMyBatisConfig
package com.ss.emergency_systemctl.config;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* MySQL数据源的MyBatis配置
* 扫描指定包下的Mapper,绑定MySQL数据源
*/
@Configuration
@MapperScan(
basePackages = "com.ss.emergency_systemctl.mapper.mysql",
sqlSessionTemplateRef = "mysqlSqlSessionTemplate"
)
public class MysqlMyBatisConfig {
@Resource
private DataSource mysqlDataSource;
@Bean(name = "mysqlSqlSessionFactory")
public SqlSessionFactory mysqlSqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
// 设置数据源
factoryBean.setDataSource(mysqlDataSource);
// 设置Mapper XML文件路径
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/mysql/*.xml")
);
// 设置别名包
factoryBean.setTypeAliasesPackage("com.ss.emergency_systemctl.entity.mysql");
// 🔥 去掉手动创建Configuration的代码,复用全局配置
return factoryBean.getObject();
}
@Bean(name = "mysqlSqlSessionTemplate")
public SqlSessionTemplate mysqlSqlSessionTemplate(
@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
PostgresMyBatisConfig
package com.ss.emergency_systemctl.config;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* PostgreSQL数据源的MyBatis配置
* 扫描指定包下的Mapper,绑定PostgreSQL数据源
*/
@Configuration
@MapperScan(
basePackages = "com.ss.emergency_systemctl.mapper.postgres",
sqlSessionTemplateRef = "postgresSqlSessionTemplate"
)
public class PostgresMyBatisConfig {
@Resource
private DataSource postgresDataSource;
@Bean(name = "postgresSqlSessionFactory")
public SqlSessionFactory postgresSqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
// 设置数据源
factoryBean.setDataSource(postgresDataSource);
// 设置Mapper XML文件路径
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/postgres/*.xml")
);
// 设置别名包(和全局配置一致)
factoryBean.setTypeAliasesPackage("com.ss.emergency_systemctl.entity.postgres");
// 🔥 去掉手动创建Configuration的代码,复用application.yml中的mybatis.configuration配置
return factoryBean.getObject();
}
@Bean(name = "postgresSqlSessionTemplate")
public SqlSessionTemplate postgresSqlSessionTemplate(
@Qualifier("postgresSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
DataSourceConfig
package com.ss.emergency_systemctl.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* 多数据源配置类
* 主数据源:PostgreSQL(标注@Primary)
* 次数据源:MySQL
*/
@Configuration
public class DataSourceConfig {
// ========== 主数据源:PostgreSQL ==========
@Bean(name = "postgresDataSource")
@Primary // 标记为主数据源,解决多数据源时的默认注入问题
@ConfigurationProperties(prefix = "spring.datasource.postgres")
public DataSource postgresDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
// ========== 次数据源:MySQL ==========
@Bean(name = "mysqlDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mysql")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
// ========== 事务管理器:PostgreSQL ==========
@Bean(name = "postgresTransactionManager")
@Primary
public PlatformTransactionManager postgresTransactionManager(
@Qualifier("postgresDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// ========== 事务管理器:MySQL ==========
@Bean(name = "mysqlTransactionManager")
public PlatformTransactionManager mysqlTransactionManager(
@Qualifier("mysqlDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
工程目录都可以创建包分类出来
每个包都可以分类:如 Controller(mysql,postgres)等等
四、注意事项
1. 数据源适配
- 禁止在 PostgreSQL 的 MyBatis XML 中使用 MySQL 专属函数(如
GROUP_CONCAT),反之亦然; - 若需跨库联查,需通过程序层整合(避免直接数据库联表,因两库无直接连接)。
2. 事务管理
-
操作 MySQL 数据时,必须指定事务管理器
mysqlTransactionManager, -
否则会默认使用 PostgreSQL 的事务管理器导致事务失效;
-
避免在一个事务中同时操作两个数据源(分布式事务需额外配置,当前架构暂不支持)。
四、只有这些场景才必须用事务 + 指定管理器
当你的 MySQL 操作包含「增 / 删 / 改」时,才需要加事务注解并指定管理器,比如:
java
运行
// 示例:修改MySQL数据时,必须指定事务管理器
@Transactional(transactionManager = "mysqlTransactionManager")
public void updateModuleData(String qhmc, List<String> newModuleIds) {
// 1. 删除旧数据
dataPushTableMapper.deleteByQhmc(qhmc);
// 2. 插入新数据
dataPushTableMapper.batchInsert(qhmc, newModuleIds);
// 若步骤1/2有一个失败,事务会回滚,避免数据不一致
}
3. 配置校验
- 启动前需验证
DataSourceConfig被 Spring 扫描(主启动类包名需覆盖config子包); - 编译后检查 XML 文件路径与内容:MySQL 的 XML 需在
mapper/mysql目录,且namespace与 Mapper 接口全类名一致。
多数据源适配核心总结
一、核心背景与架构
因业务拓展需对接外部推送的业务数据,系统采用「PostgreSQL(本地基础库)+ MySQL(业务数据使用库)」双数据源架构:
- PostgreSQL:存储系统核心基础配置、元数据,作为主数据源(标记
@Primary); - MySQL:存储外部推送的业务明细数据(如
表一/表二等表),作为次数据源。
二、核心实现要点
1. 数据源隔离配置
- 通过
DataSourceConfig类创建两个命名化DataSourceBean(postgresDataSource/mysqlDataSource),并绑定application.yml中的连接信息; - 为两个数据源配置独立的 MyBatis 规则:PostgreSQL 对应
mapper/postgres目录(SQL 用STRING_AGG),MySQL 对应mapper/mysql目录(SQL 用GROUP_CONCAT),避免语法冲突。
2. 数据操作规范
- 查询层面:PostgreSQL Mapper 操作基础库,MySQL Mapper 操作业务推送表,Service 层通过注入对应包下的 Mapper 实现分库查询;
- 事务层面 :纯查询操作无需事务注解;MySQL 增删改操作需显式指定
@Transactional(transactionManager = "mysqlTransactionManager"),避免默认使用 PostgreSQL 事务管理器导致事务失效;
三、关键注意事项
- 语法适配 :严格区分数据源 SQL 语法,禁止跨库混用专属函数(如 MySQL 的
GROUP_CONCAT不可用于 PostgreSQL); - 配置校验 :确保
DataSourceConfig被 Spring 扫描、Mapper 接口 / XML 文件名与namespace匹配,避免「找不到 Bean」「绑定语句不存在」等报错; - 事务边界:禁止在一个事务中同时操作两个数据源,纯查询无需事务注解,仅增删改需指定 MySQL 事务管理器。
四、核心结论
本次多数据源适配实现了「基础库与业务库的隔离管理、数据查询的跨库整合」,核心原则为:数据源按用途隔离配置,SQL 按数据源语法适配,事务按操作类型精准管控,既保障了数据操作的正确性,也满足了业务拓展对多数据源的使用需求。