MyBatis 多数据源切换

你是一个java开发高手,现在要给一个0基础的小白讲清楚:在 使用mybatis的时候,代码层面 是在哪里 调用的 datasource ,如何创建的 sqlsession,如果遇到多数据源 如何在调用mapper时 手动切换 数据源连接信息。
 

1. 在使用 MyBatis 时,代码层面在哪里调用的 DataSource

1.1 理解 DataSource 的作用

DataSource 是 Java 中用于获取数据库连接的接口,MyBatis 使用它来管理数据库连接。在 MyBatis 里,DataSource 负责提供数据库连接,以便执行 SQL 语句。

1.2 代码层面调用 DataSource 的位置

在 MyBatis 中,DataSource 通常在配置 SqlSessionFactory 时被使用。SqlSessionFactory 是 MyBatis 的核心组件,用于创建 SqlSession 对象,而 SqlSession 则用于执行 SQL 操作。以下是一个简单的示例:

java
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import java.sql.SQLException;

public class MyBatisExample {
    public static void main(String[] args) throws SQLException {
        // 创建 DataSource
        PooledDataSource dataSource = new PooledDataSource();
        dataSource.setDriver("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("password");

        // 创建事务工厂
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        // 创建环境
        Environment environment = new Environment("development", transactionFactory, dataSource);
        // 创建配置对象
        Configuration configuration = new Configuration(environment);
        // 这里可以添加映射器类
        // configuration.addMapper(UserMapper.class);

        // 创建 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

        // 使用 SqlSessionFactory 创建 SqlSession
        try (SqlSession session = sqlSessionFactory.openSession()) {
            // 这里可以执行 SQL 操作
        }
    }
}
 

在上述代码中,PooledDataSource 是 MyBatis 提供的一个连接池实现,我们在创建 SqlSessionFactory 之前先创建了 DataSource,并将其传递给 Environment 对象,最终传递给 Configuration 对象,这样 SqlSessionFactory 就知道从哪里获取数据库连接了。

2. 如何创建 SqlSession

2.1 通过 SqlSessionFactory 创建 SqlSession

SqlSession 是 MyBatis 执行 SQL 操作的核心对象,它提供了执行 SQL 语句、管理事务等功能。创建 SqlSession 的步骤如下:

  1. 创建 DataSource
  2. 创建 TransactionFactory
  3. 创建 Environment
  4. 创建 Configuration
  5. 使用 SqlSessionFactoryBuilder 构建 SqlSessionFactory
  6. 使用 SqlSessionFactory 创建 SqlSession

以下是示例代码:

java
 
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import java.sql.SQLException;

public class CreateSqlSessionExample {
    public static void main(String[] args) throws SQLException {
        // 创建 DataSource
        PooledDataSource dataSource = new PooledDataSource();
        dataSource.setDriver("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("password");

        // 创建事务工厂
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        // 创建环境
        Environment environment = new Environment("development", transactionFactory, dataSource);
        // 创建配置对象
        Configuration configuration = new Configuration(environment);
        // 这里可以添加映射器类
        // configuration.addMapper(UserMapper.class);

        // 创建 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

        // 使用 SqlSessionFactory 创建 SqlSession
        try (SqlSession session = sqlSessionFactory.openSession()) {
            // 这里可以执行 SQL 操作
            System.out.println("SqlSession 创建成功");
        }
    }
}
 

3. 遇到多数据源时,如何在调用 Mapper 时手动切换数据源连接信息

3.1 实现思路

为了实现多数据源的手动切换,我们可以使用 ThreadLocal 来存储当前线程使用的数据源信息,然后通过 AOP 或者拦截器在执行 SQL 操作之前切换数据源。

3.2 示例代码

以下是一个简单的多数据源切换示例:
1. 创建数据源上下文类
java
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}
 
2. 创建动态数据源类
java
 
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import java.util.Map;

public class DynamicDataSource extends AbstractRoutingDataSource {
    public DynamicDataSource(Map<Object, Object> targetDataSources, Object defaultTargetDataSource) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}
 
3. 配置数据源
java
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource1() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/db1");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }

    @Bean
    public DataSource dataSource2() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/db2");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }

    @Bean
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("dataSource1", dataSource1());
        targetDataSources.put("dataSource2", dataSource2());

        return new DynamicDataSource(targetDataSources, dataSource1());
    }
}
 
4. 在调用 Mapper 时手动切换数据源
java
 
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public void doSomethingWithDataSource1() {
        DataSourceContextHolder.setDataSource("dataSource1");
        try {
            // 执行 Mapper 方法
            userMapper.selectAllUsers();
        } finally {
            DataSourceContextHolder.clearDataSource();
        }
    }

    public void doSomethingWithDataSource2() {
        DataSourceContextHolder.setDataSource("dataSource2");
        try {
            // 执行 Mapper 方法
            userMapper.selectAllUsers();
        } finally {
            DataSourceContextHolder.clearDataSource();
        }
    }
}
 

在上述代码中,我们通过 DataSourceContextHolder 来存储当前线程使用的数据源信息,DynamicDataSource 会根据 DataSourceContextHolder 中存储的信息来切换数据源。在调用 Mapper 方法之前,我们可以手动设置要使用的数据源,执行完后清除数据源信息。

这样,我们就实现了在调用 Mapper 时手动切换数据源连接信息的功能。
posted @ 2025-05-08 14:58  CharyGao  阅读(40)  评论(0)    收藏  举报