36. MyBatis如何支持多数据库操作?如何配置不同的数据源?

在许多企业级应用中,可能需要访问多个数据库。MyBatis 可以通过配置多个数据源和动态切换数据源来支持多数据库操作。下面介绍如何在 MyBatis 中配置和使用多个数据源。

1. 多数据源的基本配置

1.1 配置多个数据源

要支持多个数据源,首先需要在 Spring 或 Spring Boot 中配置不同的数据源。假设我们要连接两个数据库 db1db2,可以通过以下步骤进行配置。

Spring Boot 示例:

  • application.yml 配置文件

spring:
  datasource:
    db1:
      url: jdbc:mysql://localhost:3306/db1
      username: root
      password: password
      driver-class-name: com.mysql.cj.jdbc.Driver
    db2:
      url: jdbc:mysql://localhost:3306/db2
      username: root
      password: password
      driver-class-name: com.mysql.cj.jdbc.Driver
  • 定义数据源配置类

@Configuration
public class DataSourceConfig {
​
    @Primary
    @Bean(name = "db1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().build();
    }
​
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }
}
  • 定义 SqlSessionFactory 和 SqlSessionTemplate

@Configuration
@MapperScan(basePackages = "com.example.mapper.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class Db1MyBatisConfig {
​
    @Bean(name = "db1SqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }
​
    @Bean(name = "db1SqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
​
@Configuration
@MapperScan(basePackages = "com.example.mapper.db2", sqlSessionTemplateRef = "db2SqlSessionTemplate")
public class Db2MyBatisConfig {
​
    @Bean(name = "db2SqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }
​
    @Bean(name = "db2SqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("db2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

1.2 使用不同数据源的 Mapper

通过以上配置,不同包下的 Mapper 将使用不同的数据源。假设 UserMapper 使用 db1OrderMapper 使用 db2

@Mapper
public interface UserMapper {
    // 使用 db1 数据源
    User findUserById(Integer id);
}
​
@Mapper
public interface OrderMapper {
    // 使用 db2 数据源
    Order findOrderById(Integer id);
}

2. 动态切换数据源

有时我们需要在运行时动态地切换数据源,比如在同一个 Service 中操作不同的数据源。可以通过 Spring 的 AbstractRoutingDataSource 实现动态切换。

2.1 定义动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
​
    private static final ThreadLocal contextHolder = new ThreadLocal<>();
​
    public static void setDataSource(String dataSourceKey) {
        contextHolder.set(dataSourceKey);
    }
​
    public static String getDataSource() {
        return contextHolder.get();
    }
​
    public static void clearDataSource() {
        contextHolder.remove();
    }
​
    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }
}

2.2 配置数据源和 SqlSessionFactory

@Configuration
public class DynamicDataSourceConfig {
​
    @Bean
    @Primary
    public DataSource dataSource(@Qualifier("db1DataSource") DataSource db1DataSource,
                                 @Qualifier("db2DataSource") DataSource db2DataSource) {
        Map targetDataSources = new HashMap<>();
        targetDataSources.put("db1", db1DataSource);
        targetDataSources.put("db2", db2DataSource);
​
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(db1DataSource);
        return dynamicDataSource;
    }
​
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        return sessionFactoryBean.getObject();
    }
​
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

2.3 在 Service 中动态切换数据源

@Service
public class UserService {
​
    @Autowired
    private UserMapper userMapper;
​
    @Autowired
    private OrderMapper orderMapper;
​
    public User getUserFromDb1(Integer id) {
        DynamicDataSource.setDataSource("db1");
        try {
            return userMapper.findUserById(id);
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }
​
    public Order getOrderFromDb2(Integer id) {
        DynamicDataSource.setDataSource("db2");
        try {
            return orderMapper.findOrderById(id);
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }
}

3. 总结

MyBatis 支持通过配置多个数据源和动态切换数据源来实现多数据库操作:

  1. 多数据源静态配置:通过在 Spring 配置中定义多个 DataSourceSqlSessionFactorySqlSessionTemplate 来实现静态多数据源支持。不同包下的 Mapper 自动使用指定的数据源。

  2. 动态数据源切换:通过实现 AbstractRoutingDataSource 动态数据源切换机制,能够在运行时动态地选择不同的数据源,这对于需要在同一事务中切换不同数据库操作的场景特别有用。

通过这些方法,MyBatis 可以灵活地支持多数据库操作,以满足复杂的业务需求。

你可能感兴趣的:(Mybatis笔记,mybatis,数据库)