在现代企业应用中,常常需要与多个数据库交互,比如分布式数据库、读写分离、业务拆分等场景。MyBatis-Plus 作为 MyBatis 的增强工具,支持多数据源的集成,可以帮助开发者轻松管理和切换多个数据库连接。

一、MyBatis-Plus 多数据源的使用场景

  1. 业务拆分:不同业务模块使用不同的数据库,比如用户信息存储在一个数据库,订单信息存储在另一个数据库。
  2. 读写分离:通过主从数据库配置,将写操作指向主库,读操作指向从库。
  3. 分布式数据库:不同的数据库实例存储不同的数据,通过路由规则选择不同的数据源。

二、MyBatis-Plus 多数据源的实现原理

MyBatis-Plus 多数据源的实现依赖于 Spring 框架的多数据源支持。通过为不同的数据源配置独立的 DataSourceSqlSessionFactory,实现多个数据库连接的管理。结合 DynamicDataSource,可以根据业务需求动态切换数据源。

三、配置步骤

1. 引入依赖

首先,确保项目中已经引入了 MyBatis-Plus 和相关的数据库驱动。以 MySQL 为例,可以在 pom.xml 文件中引入以下依赖:

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

    <!-- MySQL 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>
2. 配置多数据源

application.yml 中配置多个数据源。这里我们配置两个 MySQL 数据源,分别为 masterslave 数据源,模拟读写分离的场景。

spring:
  datasource:
    master:
      url: jdbc:mysql://localhost:3306/master_db?useSSL=false&serverTimezone=UTC
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      url: jdbc:mysql://localhost:3306/slave_db?useSSL=false&serverTimezone=UTC
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  mapper-locations: classpath:mapper/**/*.xml
  type-aliases-package: com.example.demo.model
  • master:主库,处理写操作。
  • slave:从库,处理读操作。
3. 配置数据源 DataSource

接下来,我们为 masterslave 数据源分别配置 DataSource。创建一个 DataSourceConfig 类,定义不同的数据源和动态数据源的切换。

package com.example.demo.config;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.YmlDynamicDataSourceProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    // 主数据源 master
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 从数据源 slave
    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 动态数据源
    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        return new YmlDynamicDataSourceProvider();
    }
}
4. 配置 DynamicDataSource 实现动态数据源切换

使用 MyBatis-Plus 提供的 @DS 注解,可以很方便地实现数据源的动态切换。在 @Service 层或者 @Mapper 层,通过 @DS 注解来指定不同的数据源。

package com.example.demo.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    // 使用主库(master)进行操作
    @DS("master")
    public void saveUser(User user) {
        userMapper.insert(user);
    }

    // 使用从库(slave)进行查询
    @DS("slave")
    public List<User> getAllUsers() {
        return userMapper.selectList(null);
    }
}
  • @DS("master"):表示该方法将使用 master 数据源。
  • @DS("slave"):表示该方法将使用 slave 数据源。

在这个例子中,saveUser() 方法使用主库 master 进行写操作,getAllUsers() 方法使用从库 slave 进行查询。

5. 创建 Mapper 接口

与单一数据源的配置类似,我们需要创建 Mapper 接口用于数据库的操作。这里使用 MyBatis-Plus 的 BaseMapper 接口来进行 CRUD 操作。

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}
6. 测试多数据源切换

编写 UserController 来测试多数据源的读写分离。

package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 保存用户(写操作,使用主库)
    @PostMapping
    public String saveUser(@RequestBody User user) {
        userService.saveUser(user);
        return "用户保存成功";
    }

    // 查询所有用户(读操作,使用从库)
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
}
  • POST /users:调用 saveUser() 方法,使用主库 master 进行写操作。
  • GET /users:调用 getAllUsers() 方法,使用从库 slave 进行查询操作。

四、常见场景

1. 读写分离

在实际应用中,常见的多数据源场景是 读写分离。写操作指向主库,而读操作指向从库。通过 MyBatis-Plus 提供的动态数据源切换,开发者只需在代码中标注 @DS("master")@DS("slave"),就能轻松实现读写分离。

例如:

  • 插入数据时使用 master 数据源:
    @DS("master")
    public void insertData(User user) {
        userMapper.insert(user);
    }
    
  • 查询数据时使用 slave 数据源:
    @DS("slave")
    public List<User> selectAllUsers() {
        return userMapper.selectList(null);
    }
    
2. 不同业务模块使用不同数据库

在某些系统中,不同的业务模块会使用不同的数据库,例如用户模块和订单模块分别使用不同的数据源。这时我们可以通过 @DS 注解为不同的业务模块配置不同的数据源。

例如:

  • 用户模块使用 user_db 数据源:
    @DS("user_db")
    public User findUserById(Long id) {
        return userMapper.selectById(id);
    }
    
  • 订单模块使用 order_db 数据源:
    @DS("order_db")
    public Order findOrderById(Long id) {
        return orderMapper.selectById(id);
    }
    
3. 动态切换数据源

MyBatis-Plus 支持基于业务逻辑或其他条件动态切换数据源。例如,可以根据用户的地理位置选择不同的数据库进行查询。

public User getUserBasedOnRegion(String region, Long id) {
    if ("US".equals(region)) {
        return userService.findUserById(id); // 使用 US 数据源
    } else {
        return userService.findUserByIdInOtherRegion(id); // 使用其他数据源
    }
}

五、注意事项

  1. 数据源的一致性:在使用多数据源时,需要考虑数据的一致性问题,特别是在

涉及事务的场景下。
2. 事务管理:MyBatis-Plus 结合 Spring 的事务管理可以实现跨数据源的事务控制,但需要特别注意不同数据源之间的事务隔离。
3. 性能优化:合理使用从库可以减轻主库的压力,但要确保从库的数据及时同步,避免读到不一致的数据。

六、总结

通过 MyBatis-Plus 的多数据源支持,开发者可以轻松实现 读写分离业务模块分离 以及其他复杂的多数据源场景。通过简单的注解配置,动态数据源切换变得十分灵活和高效。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐