MyBatis如何实现动态数据源切换?

大家好,我是锋哥。今天分享关于【MyBatis如何实现动态数据源切换?】**面试题。**希望对大家有帮助;

MyBatis如何实现动态数据源切换?

超硬核AI学习资料,现在永久免费了!

在MyBatis中实现动态数据源切换,通常需要依赖Spring的动态数据源管理机制,结合一些自定义的切换策略。以下是实现动态数据源切换的基本步骤:

1. 配置数据源

首先,在配置文件中配置多个数据源。例如,配置两个数据源:masterDataSourceslaveDataSource

复制代码
<bean id="masterDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/master_db"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

<bean id="slaveDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/slave_db"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

2. 定义动态数据源

创建一个自定义的数据源类,它能够切换不同的数据源。AbstractRoutingDataSource 是Spring提供的一个抽象类,适用于实现动态数据源。

复制代码
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        // 返回当前的数据源标识(如:master 或 slave)
        return DataSourceContextHolder.getDataSourceType();
    }
}

3. 数据源上下文管理

为了管理当前使用的数据源,可以创建一个 DataSourceContextHolder 类,用来存储和获取当前线程的数据源标识。

复制代码
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

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

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

4. 配置动态数据源

在Spring配置中使用 DynamicDataSource 替代传统的单一数据源。

复制代码
<bean id="dataSource" class="com.example.DynamicDataSource">
    <property name="defaultTargetDataSource" ref="masterDataSource"/>
    <property name="targetDataSources">
        <map>
            <entry key="master" value-ref="masterDataSource"/>
            <entry key="slave" value-ref="slaveDataSource"/>
        </map>
    </property>
</bean>

5. AOP实现数据源切换

使用Spring AOP(面向切面编程)来切换数据源。可以通过注解或者在方法执行前动态修改当前线程的 DataSource

例如,创建一个注解 @DataSource 来标记需要切换数据源的方法:

复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value() default "master"; // 默认使用master数据源
}

然后,创建一个切面(Aspect),根据注解切换数据源:

复制代码
@Aspect
@Component
public class DataSourceAspect {
    @Before("@annotation(dataSource)")
    public void changeDataSource(DataSource dataSource) {
        // 切换数据源
        DataSourceContextHolder.setDataSourceType(dataSource.value());
    }

    @After("@annotation(dataSource)")
    public void restoreDataSource(DataSource dataSource) {
        // 切换回默认数据源
        DataSourceContextHolder.clearDataSourceType();
    }
}

6. 在服务层使用注解切换数据源

在需要切换数据源的方法上使用 @DataSource 注解:

复制代码
@Service
public class UserService {

    @DataSource("master")  // 使用master数据源
    public void addUser(User user) {
        // 执行数据库操作
    }

    @DataSource("slave")  // 使用slave数据源
    public List<User> getUsers() {
        // 执行数据库查询
        return userRepository.findAll();
    }
}

7. 使用完毕后清理数据源

在每次请求结束后,确保清理 ThreadLocal 中存储的数据源标识,避免线程池复用时出现错误。

复制代码
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

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

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

总结:

  • 数据源管理 :使用 DynamicDataSource 来管理多个数据源。
  • 数据源切换 :通过 DataSourceContextHolder 类和Spring AOP机制,在方法执行时切换数据源。
  • 使用场景:动态切换数据源通常用于读写分离,或者多数据库操作的场景。

这样,你就可以在 MyBatis 中根据需要动态地切换数据源了。