springboot mybaits 连接多数据源
-----------------------------------------------------------------------------------------------------------
在 Spring Boot 中使用 MyBatis 连接多数据源,通常可以通过配置多个数据源实例并绑定不同的 Mapper 路径来实现。以下是详细步骤:
1. 准备依赖
在
pom.xml 中添加必要依赖(以 MySQL 为例):xml
<!-- Spring Boot 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis 整合 Spring Boot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 数据源配置(可选,Spring Boot 2.0+ 自带 HikariCP) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
2. 配置多数据源信息
在
application.yml 中配置多个数据源的连接信息(以两个数据源为例):yaml
spring:
datasource:
# 主数据源(primary)
primary:
jdbc-url: jdbc:mysql://localhost:3306/db1?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 第二个数据源(secondary)
secondary:
jdbc-url: jdbc:mysql://localhost:3306/db2?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis 配置(可选,如 mapper 位置、别名等)
mybatis:
type-aliases-package: com.example.entity # 实体类包路径
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
3. 配置数据源实例
创建配置类,分别实例化两个数据源,并指定主数据源(
@Primary)。主数据源配置(PrimaryDataSourceConfig)
java
运行
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
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.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
// 扫描主数据源对应的 Mapper 接口,并指定 SqlSessionFactory
@MapperScan(
basePackages = "com.example.mapper.primary", // 主数据源的 Mapper 路径
sqlSessionFactoryRef = "primarySqlSessionFactory"
)
public class PrimaryDataSourceConfig {
// 实例化主数据源
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary") // 绑定配置前缀
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
// 主数据源的 SqlSessionFactory
@Primary
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactoryBean primarySqlSessionFactory(
@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 指定主数据源的 Mapper XML 路径(如果有)
sessionFactory.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mybatis/primary/*.xml") // 例如:resources/mybatis/primary/
);
return sessionFactory;
}
}
第二个数据源配置(SecondaryDataSourceConfig)
java
运行
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
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.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
// 扫描第二个数据源对应的 Mapper 接口
@MapperScan(
basePackages = "com.example.mapper.secondary", // 第二个数据源的 Mapper 路径
sqlSessionFactoryRef = "secondarySqlSessionFactory"
)
public class SecondaryDataSourceConfig {
// 实例化第二个数据源
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
// 第二个数据源的 SqlSessionFactory
@Bean(name = "secondarySqlSessionFactory")
public SqlSessionFactoryBean secondarySqlSessionFactory(
@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 指定第二个数据源的 Mapper XML 路径
sessionFactory.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mybatis/secondary/*.xml") // 例如:resources/mybatis/secondary/
);
return sessionFactory;
}
}
4. 编写 Mapper 和实体类
- 主数据源的 Mapper 接口放在
com.example.mapper.primary包下,对应的 XML 文件放在resources/mybatis/primary/下。 - 第二个数据源的 Mapper 接口放在
com.example.mapper.secondary包下,对应的 XML 文件放在resources/mybatis/secondary/下。
示例(主数据源 Mapper):
java
运行
// com.example.mapper.primary.UserMapper.java
public interface UserMapper {
User getById(Long id);
}
对应的 XML:
xml
<!-- resources/mybatis/primary/UserMapper.xml -->
<mapper namespace="com.example.mapper.primary.UserMapper">
<select id="getById" resultType="com.example.entity.User">
select * from user where id = #{id}
</select>
</mapper>
5. 使用数据源
在 Service 中直接注入对应的 Mapper 即可自动使用绑定的数据源:
java
运行
@Service
public class UserService {
@Autowired
private UserMapper userMapper; // 自动关联主数据源
@Autowired
private OrderMapper orderMapper; // 自动关联第二个数据源(假设 OrderMapper 在 secondary 包下)
public User getUser(Long id) {
return userMapper.getById(id); // 查询 db1
}
public Order getOrder(Long id) {
return orderMapper.getById(id); // 查询 db2
}
}
关键说明
- @Primary 注解:必须指定一个主数据源,否则 Spring 会因无法确定默认数据源而报错。
- Mapper 路径隔离:通过
@MapperScan的basePackages区分不同数据源的 Mapper,避免冲突。 - 事务管理:如果需要事务,需为每个数据源配置
DataSourceTransactionManager,并在 Service 中通过@Transactional(value = "事务管理器名称")指定。
例如,为主数据源添加事务管理器:
java
运行
@Primary
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager primaryTransactionManager(
@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
使用时:
java
运行
@Transactional(value = "primaryTransactionManager")
public void saveUser(User user) {
userMapper.insert(user);
}
通过以上步骤,即可实现 Spring Boot + MyBatis 多数据源的配置和使用。如果需要更多数据源,按相同逻辑添加配置类即可。
-----------------------------------------------------------------------------------------------------------
Spring Boot 中使用 MyBatis 连接多数据源 事务控制
在 Spring Boot + MyBatis 多数据源场景中,事务控制需要为每个数据源单独配置事务管理器,并通过
@Transactional 注解指定使用哪个事务管理器。以下是详细实现步骤:1. 为每个数据源配置事务管理器
多数据源环境下,每个数据源需要对应一个独立的事务管理器(
DataSourceTransactionManager)。在之前的数据源配置类中添加事务管理器的定义:主数据源配置类(补充事务管理器)
java
运行
@Configuration
@MapperScan(
basePackages = "com.example.mapper.primary",
sqlSessionFactoryRef = "primarySqlSessionFactory"
)
public class PrimaryDataSourceConfig {
// 主数据源(省略,同上)
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
// 主数据源 SqlSessionFactory(省略,同上)
@Primary
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactoryBean primarySqlSessionFactory(
@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
// ... 同上
}
// 主数据源事务管理器(新增)
@Primary // 主事务管理器也需要加 @Primary
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager primaryTransactionManager(
@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
第二个数据源配置类(补充事务管理器)
java
运行
@Configuration
@MapperScan(
basePackages = "com.example.mapper.secondary",
sqlSessionFactoryRef = "secondarySqlSessionFactory"
)
public class SecondaryDataSourceConfig {
// 第二个数据源(省略,同上)
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
// 第二个数据源 SqlSessionFactory(省略,同上)
@Bean(name = "secondarySqlSessionFactory")
public SqlSessionFactoryBean secondarySqlSessionFactory(
@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
// ... 同上
}
// 第二个数据源事务管理器(新增)
@Bean(name = "secondaryTransactionManager")
public DataSourceTransactionManager secondaryTransactionManager(
@Qualifier("secondaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2. 在 Service 中指定事务管理器
通过
@Transactional 注解的 value 属性(或 transactionManager 属性,两者等价)指定使用哪个事务管理器。示例:单数据源事务
java
运行
@Service
public class UserService {
@Autowired
private UserMapper userMapper; // 主数据源的 Mapper
@Autowired
private OrderMapper orderMapper; // 第二个数据源的 Mapper
// 使用主数据源的事务管理器
@Transactional(value = "primaryTransactionManager", rollbackFor = Exception.class)
public void saveUser(User user) {
userMapper.insert(user);
// 如果发生异常,会回滚主数据源的操作
if (user.getId() == null) {
throw new RuntimeException("保存用户失败");
}
}
// 使用第二个数据源的事务管理器
@Transactional(value = "secondaryTransactionManager", rollbackFor = Exception.class)
public void saveOrder(Order order) {
orderMapper.insert(order);
// 如果发生异常,会回滚第二个数据源的操作
}
}
3. 跨数据源事务(分布式事务)
如果需要在一个方法中操作多个数据源,且要求 “要么都成功,要么都失败”,单靠本地事务管理器无法实现(本地事务只能管理单个数据源),此时需要分布式事务方案。
常用的分布式事务实现方式:
- Seata:阿里开源的分布式事务框架,支持 AT、TCC 等模式,集成简单。
- Hmily:基于 TCC 模式的分布式事务框架。
- 2PC:传统分布式事务协议(性能较差,不推荐)。
以 Seata 为例的简单集成步骤:
-
添加 Seata 依赖:xml
<dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.6.1</version> </dependency> -
配置 Seata(
application.yml):yamlseata: tx-service-group: my_test_tx_group # 事务组名称(需与 Seata 服务器配置一致) registry: type: nacos # 注册中心类型(如 nacos、eureka 等) nacos: server-addr: 127.0.0.1:8848 config: type: nacos nacos: server-addr: 127.0.0.1:8848 -
使用分布式事务注解:在跨数据源的方法上添加
@GlobalTransactional(Seata 提供的分布式事务注解),替代@Transactional:java运行@Service public class OrderService { @Autowired private UserMapper userMapper; // 主数据源 @Autowired private OrderMapper orderMapper; // 第二个数据源 // 分布式事务:同时操作两个数据源 @GlobalTransactional(rollbackFor = Exception.class) public void createOrderAndUpdateUser(Order order, Long userId) { // 操作主数据源 userMapper.updateBalance(userId, order.getAmount()); // 操作第二个数据源 orderMapper.insert(order); // 如果发生异常,Seata 会协调两个数据源回滚 if (order.getId() == null) { throw new RuntimeException("创建订单失败"); } } }
关键注意事项
- 本地事务限制:
@Transactional只能控制单个数据源的事务,跨数据源操作时需用分布式事务框架。 - 事务管理器名称:
@Transactional(value = "xxxTransactionManager")中的名称必须与配置类中@Bean(name = "xxxTransactionManager")一致。 - rollbackFor 属性:默认情况下,事务只对
RuntimeException回滚,建议显式指定rollbackFor = Exception.class确保所有异常都回滚。 - 分布式事务成本:分布式事务会降低性能并增加复杂度,非必要场景建议避免跨数据源事务(例如通过业务设计将相关操作放在同一数据源)。
-----------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------

浙公网安备 33010602011771号