大家好,我是锋哥。今天分享关于【MyBatis如何实现动态数据源切换?】**面试题。**希望对大家有帮助;
MyBatis如何实现动态数据源切换?
在MyBatis中实现动态数据源切换,通常需要依赖Spring的动态数据源管理机制,结合一些自定义的切换策略。以下是实现动态数据源切换的基本步骤:
1. 配置数据源
首先,在配置文件中配置多个数据源。例如,配置两个数据源:masterDataSource
和 slaveDataSource
。
<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 中根据需要动态地切换数据源了。