springboot mybatis-plus 集成多数据源
在 Spring Boot 项目中集成 MyBatis-Plus 并配置多数据源,可以按照以下步骤进行。这个示例将展示如何配置两个数据源,并确保每个数据源都有自己对应的 SqlSessionFactory 和事务管理器。
1. 添加依赖
首先,在你的 pom.xml 文件中添加必要的依赖项:
<dependencies>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MyBatis-Plus Boot Starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>最新版本号</version>
</dependency>
<!-- MySQL Connector Java (根据实际使用的数据库选择) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- HikariCP (Spring Boot 默认的连接池) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
</dependencies>
2. 配置文件设置
在 application.yml 中配置两个数据源的相关信息:
spring:
datasource:
primary:
url: jdbc:mysql://localhost:3306/primary_db?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
secondary:
url: jdbc:mysql://localhost:3306/secondary_db?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 启用SQL日志输出
mapper-locations: classpath:/mapper/*.xml # Mapper XML文件位置
3. 数据源配置类
创建两个配置类来分别配置主数据源和次数据源及其相关的 SqlSessionFactory 和事务管理器。
主数据源配置 (PrimaryDataSourceConfig.java)
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.hieasy.e3.mapper.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 添加MyBatis-Plus插件(如分页插件)
sessionFactory.setPlugins(new Interceptor[]{new PaginationInterceptor()});
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/primary/*.xml"));
return sessionFactory.getObject();
}
@Primary
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
次数据源配置 (SecondaryDataSourceConfig.java)
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.hieasy.e3.mapper.secondary", sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class SecondaryDataSourceConfig {
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondarySqlSessionFactory")
public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 添加MyBatis-Plus插件(如分页插件)
sessionFactory.setPlugins(new Interceptor[]{new PaginationInterceptor()});
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/secondary/*.xml"));
return sessionFactory.getObject();
}
@Bean(name = "secondaryTransactionManager")
public DataSourceTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
3.1 关键配置说明
1. 使用 MybatisSqlSessionFactoryBean
而非默认工厂
-
原因:MyBatis-Plus 的功能(如默认方法)依赖其自定义的
SqlSessionFactory
。 -
错误示例:使用原生
SqlSessionFactoryBean
会导致插件失效。
2. 指定独立的Mapper包路径
-
通过
@MapperScan(basePackages = "包路径", sqlSessionFactoryRef = "工厂Bean名称")
确保每个数据源的Mapper绑定到正确的工厂。 -
包路径分离:将不同数据源的Mapper接口分别放在不同的包中(如
com.example.mapper.db1
和com.example.mapper.db2
)。
3. 添加MyBatis-Plus插件
-
在
SqlSessionFactory
中注入插件(如分页插件、乐观锁插件),否则分页等增强功能失效:
4. Mapper 接口定义
确保为每个数据源定义的 Mapper 接口位于正确的包下,并继承 BaseMapper。
主数据源 Mapper 示例 (PrimaryMapper.java)
package com.hieasy.e3.mapper.primary;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hieasy.e3.entity.PrimaryEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PrimaryMapper extends BaseMapper<PrimaryEntity> {
}
次数据源 Mapper 示例 (SecondaryMapper.java)
package com.hieasy.e3.mapper.secondary;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hieasy.e3.entity.SecondaryEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SecondaryMapper extends BaseMapper<SecondaryEntity> {
}
5. 使用示例
在服务层或控制器中使用这些 Mapper 进行操作时,请确保正确注入它们:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class MultiDataSourceService {
private final PrimaryMapper primaryMapper;
private final SecondaryMapper secondaryMapper;
@Autowired
public MultiDataSourceService(PrimaryMapper primaryMapper, SecondaryMapper secondaryMapper) {
this.primaryMapper = primaryMapper;
this.secondaryMapper = secondaryMapper;
}
@Transactional("primaryTransactionManager")
public void operateOnPrimary() {
// 对主数据源的操作
}
@Transactional("secondaryTransactionManager")
public void operateOnSecondary() {
// 对次数据源的操作
}
}
6. 避免自动配置冲突
若手动配置多数据源,需排除Spring Boot的默认数据源自动配置:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
常见问题排查
-
错误提示
Invalid bound statement (not found)
:-
检查Mapper接口的包路径是否在
@MapperScan
中正确指定。 -
确认XML映射文件(若有)路径是否在配置中指定。
-
-
分页/乐观锁失效:
-
检查是否在
SqlSessionFactory
中添加了对应插件。
-
-
事务不生效:
-
确保在方法上使用
@Transactional(transactionManager = "db1TransactionManager")
指定事务管理器。
-