springboot中怎么利用mybatis-plus 配置多数据源

发布时间:2021-06-22 16:19:21 作者:Leah
来源:亿速云 阅读:576
# SpringBoot中怎么利用MyBatis-Plus配置多数据源

## 前言

在现代企业级应用开发中,多数据源的需求变得越来越普遍。无论是读写分离、分库分表,还是需要同时访问多个不同类型的数据库,多数据源配置都成为了开发者必须掌握的技能。MyBatis-Plus作为MyBatis的增强工具,在多数据源场景下提供了简洁高效的解决方案。本文将详细介绍在SpringBoot项目中如何利用MyBatis-Plus配置和使用多数据源。

## 一、多数据源应用场景

### 1.1 常见使用场景

- **读写分离**:主库负责写操作,从库负责读操作
- **分库分表**:数据水平拆分到不同数据库实例
- **多租户系统**:每个租户使用独立的数据源
- **异构数据库**:同时访问MySQL、Oracle等不同数据库

### 1.2 技术选型对比

| 方案               | 优点                          | 缺点                          |
|--------------------|-----------------------------|-----------------------------|
| 原生JDBC           | 灵活性强                    | 代码冗余,维护成本高          |
| Spring AbstractRoutingDataSource | 与Spring集成好       | 需要自行实现路由逻辑          |
| MyBatis-Plus多数据源 | 配置简单,功能完善          | 需要引入额外依赖              |

## 二、环境准备

### 2.1 项目依赖

```xml
<!-- Spring Boot Starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- MyBatis-Plus Starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

<!-- 多数据源核心依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.6.1</version>
</dependency>

<!-- 数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- 其他工具 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

2.2 数据库准备

准备两个数据库实例,本文示例使用: - 主库:ds1 (端口3306) - 从库:ds2 (端口3307)

三、基础配置

3.1 配置文件

application.yml 配置示例:

spring:
  datasource:
    dynamic:
      primary: master # 设置默认数据源
      strict: false  # 是否严格匹配数据源
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/ds1?useSSL=false&serverTimezone=UTC
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave:
          url: jdbc:mysql://localhost:3307/ds2?useSSL=false&serverTimezone=UTC
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver

3.2 数据源配置类

@Configuration
@MapperScan(basePackages = "com.example.mapper")
public class DataSourceConfig {
    
    /**
     * 无需@Bean注解,dynamic-datasource会自动配置
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

四、多数据源使用方式

4.1 注解方式切换数据源

@DS 注解使用

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    
    // 默认使用主数据源
    @Override
    public User getMasterUser(Long id) {
        return userMapper.selectById(id);
    }
    
    // 指定从数据源
    @DS("slave")
    @Override
    public User getSlaveUser(Long id) {
        return userMapper.selectById(id);
    }
}

注解作用范围

4.2 编程式切换数据源

public class DataSourceContextHolder {
    
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    
    public static void setDataSource(String dsName) {
        CONTEXT_HOLDER.set(dsName);
    }
    
    public static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }
    
    public static void clearDataSource() {
        CONTEXT_HOLDER.remove();
    }
}

// 使用示例
public List<User> getAllUsers() {
    try {
        DataSourceContextHolder.setDataSource("slave");
        return userMapper.selectList(null);
    } finally {
        DataSourceContextHolder.clearDataSource();
    }
}

五、高级特性配置

5.1 多数据源事务管理

@Service
public class OrderService {
    
    @DS("master")
    @Transactional
    public void createOrder(Order order) {
        // 主库操作
        orderMapper.insert(order);
        
        // 切换数据源需要新开事务
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        transactionTemplate.execute(status -> {
            try {
                DataSourceContextHolder.setDataSource("slave");
                // 从库操作
                logMapper.insertLog(order);
                return true;
            } finally {
                DataSourceContextHolder.clearDataSource();
            }
        });
    }
}

5.2 动态添加数据源

@Autowired
private DynamicRoutingDataSource dynamicRoutingDataSource;

public void addNewDataSource(String dsName, DataSourceProperty property) {
    DataSource dataSource = dynamicDataSourceCreator.createDataSource(property);
    dynamicRoutingDataSource.addDataSource(dsName, dataSource);
}

5.3 多租户数据源隔离

public class TenantDataSourceSelector {
    
    public static String determineCurrentLookupKey() {
        // 从当前线程获取租户信息
        String tenantId = TenantContext.getCurrentTenant();
        return "tenant_" + tenantId;
    }
}

// 配置类添加
@Bean
public AbstractRoutingDataSource multiTenantDataSource() {
    DynamicRoutingDataSource ds = new DynamicRoutingDataSource();
    ds.setDataSourceSelector(TenantDataSourceSelector::determineCurrentLookupKey);
    return ds;
}

六、性能优化建议

6.1 连接池配置

spring:
  datasource:
    dynamic:
      datasource:
        master:
          hikari:
            maximum-pool-size: 20
            minimum-idle: 5
            connection-timeout: 30000
            idle-timeout: 600000
            max-lifetime: 1800000

6.2 多数据源监控

@RestController
@RequestMapping("/datasource")
public class DataSourceMonitorController {
    
    @Autowired
    private DynamicRoutingDataSource dynamicRoutingDataSource;
    
    @GetMapping("/stats")
    public Map<String, Object> getDataSourceStats() {
        Map<String, DataSource> dataSources = dynamicRoutingDataSource.getCurrentDataSources();
        Map<String, Object> stats = new HashMap<>();
        
        dataSources.forEach((name, ds) -> {
            if (ds instanceof HikariDataSource) {
                HikariDataSource hikari = (HikariDataSource) ds;
                stats.put(name, hikari.getHikariPoolMXBean());
            }
        });
        
        return stats;
    }
}

七、常见问题解决方案

7.1 事务不生效问题

现象:跨数据源事务无法回滚
解决方案: 1. 使用JTA分布式事务 2. 采用最终一致性方案 3. 拆分业务逻辑,避免跨库事务

7.2 数据源切换失败

排查步骤: 1. 检查@DS注解是否被AOP代理 2. 确认数据源名称拼写正确 3. 检查是否配置了strict模式

7.3 连接泄漏问题

预防措施: 1. 确保每次操作后清理ThreadLocal 2. 使用try-finally代码块 3. 配置合理的连接超时时间

八、完整示例代码

8.1 实体类

@Data
@TableName("t_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

8.2 Mapper接口

public interface UserMapper extends BaseMapper<User> {
    
    @DS("slave")
    @Select("SELECT * FROM t_user WHERE age > #{age}")
    List<User> selectUsersByAge(@Param("age") Integer age);
}

8.3 测试Controller

@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/master/{id}")
    public User getFromMaster(@PathVariable Long id) {
        return userService.getMasterUser(id);
    }
    
    @GetMapping("/slave/{id}")
    public User getFromSlave(@PathVariable Long id) {
        return userService.getSlaveUser(id);
    }
}

九、总结

本文详细介绍了在SpringBoot项目中整合MyBatis-Plus实现多数据源配置的全过程,包括:

  1. 基础环境搭建和依赖配置
  2. 多种数据源切换方式(注解/编程式)
  3. 高级特性如动态数据源、多租户支持
  4. 性能优化和问题排查方案

MyBatis-Plus的多数据源方案相比原生实现具有明显优势:

在实际项目中,建议根据具体业务场景选择合适的多数据源策略,并注意事务管理和连接泄漏问题。对于更复杂的分布式事务场景,可以考虑集成Seata等分布式事务框架。

附录

A. 推荐阅读

B. 版本说明

C. 示例项目

完整示例代码已上传至GitHub: springboot-mybatisplus-multi-ds-demo “`

推荐阅读:
  1. springboot中多数据源的实现方法
  2. 怎么在springboot中利用Mybatis实现读写分离

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot mybatis-plus

上一篇:python中怎么实现圆角半角转换

下一篇:PageHelper中怎么查询全部数据

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》