AbstractRoutingDataSource是在什么时候切换数据源的
时间: 2023-12-09 22:06:45 浏览: 29
AbstractRoutingDataSource 是一个抽象类,可以通过继承它并实现其中的抽象方法,来实现多数据源的切换。其中,最重要的方法是 determineCurrentLookupKey(),它的作用是根据当前的业务场景,返回相应的数据源的标识符。
当应用程序需要访问数据库时,会通过 AbstractRoutingDataSource 的 getConnection() 方法获取一个数据库连接。在这个方法中,会根据 determineCurrentLookupKey() 方法返回的数据源标识符,选择相应的数据源,并返回一个连接。
因此,数据源的切换是在 getConnection() 方法中进行的。在应用程序的业务逻辑中,只需要调用 getConnection() 方法获取数据库连接即可,而不需要关心具体使用了哪个数据源。
相关问题
AbstractRoutingDataSource+Mybatis拦截器实现动态切换数据源代码
下面是使用 AbstractRoutingDataSource 和 MyBatis 拦截器实现动态切换数据源的示例代码:
首先,需要自定义一个继承 AbstractRoutingDataSource 的类,并实现 determineCurrentLookupKey 方法,该方法用于返回当前数据源的 key:
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<>();
public static void setDataSourceKey(String key) {
dataSourceKey.set(key);
}
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get();
}
}
```
在 Spring 配置文件中需要配置两个数据源,并将 DynamicDataSource 设置为默认数据源:
```xml
<bean id="dataSource1" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db2"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="dynamicDataSource" class="com.example.DynamicDataSource">
<property name="defaultTargetDataSource" ref="dataSource1"/>
<property name="targetDataSources">
<map>
<entry key="db1" value-ref="dataSource1"/>
<entry key="db2" value-ref="dataSource2"/>
</map>
</property>
</bean>
```
接下来,需要实现一个继承于 MyBatis 的 Interceptor 接口的拦截器类,该类用于在执行 SQL 语句前切换数据源:
```java
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DynamicDataSourceInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
String dataSourceKey = getDataSourceKey(mappedStatement);
if (dataSourceKey != null) {
DynamicDataSource.setDataSourceKey(dataSourceKey);
}
return invocation.proceed();
}
private String getDataSourceKey(MappedStatement mappedStatement) {
String dataSourceKey = null;
// 从 Mapper 方法上获取数据源 key
if (mappedStatement != null) {
String id = mappedStatement.getId();
if (id.startsWith("com.example.mapper1")) {
dataSourceKey = "db1";
} else if (id.startsWith("com.example.mapper2")) {
dataSourceKey = "db2";
}
}
return dataSourceKey;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// do nothing
}
}
```
最后,需要在 Spring 配置文件中配置该拦截器:
```xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
<property name="plugins">
<array>
<bean class="com.example.DynamicDataSourceInterceptor"/>
</array>
</property>
</bean>
```
这样,就可以在 Mapper 方法上使用 @DataSource("db1") 或 @DataSource("db2") 注解来指定使用哪个数据源了。例如:
```java
@DataSource("db1")
List<User> getUserList();
@DataSource("db2")
int addUser(User user);
```
如何在springboot动态切换数据源
在Spring Boot中动态切换数据源可以使用AbstractRoutingDataSource类来实现。以下是实现动态数据源切换的步骤:
1. 配置数据源:在application.properties或application.yml文件中配置多个数据源的相关信息,包括数据库连接信息、用户名、密码等。
2. 创建数据源管理器:创建一个类,继承AbstractRoutingDataSource,并重写determineCurrentLookupKey方法。该方法的作用是根据当前线程的上下文/environment等信息动态确定使用哪个数据源。
3. 配置数据源管理器:在Spring Boot的配置类中添加@Bean注解,将数据源管理器注入到Spring容器中。
4. 使用数据源:在需要切换数据源的业务类或方法中,通过Spring的注解@Qualifier注解指定数据源管理器,并调用相关的数据访问接口。
下面是一个示例代码:
1. 配置多个数据源:
```java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
}
```
2. 创建数据源管理器:
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceKey();
}
}
```
3. 配置数据源管理器:
```java
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dynamicDataSource(DataSource masterDataSource, DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceKey.MASTER, masterDataSource);
targetDataSources.put(DataSourceKey.SLAVE, slaveDataSource);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
}
```
4. 使用数据源:
```java
@Service
public class UserService {
@Autowired
@Qualifier("dynamicDataSource")
private DataSource dataSource;
public List<User> getUsers() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate.query("SELECT * FROM users", new BeanPropertyRowMapper<>(User.class));
}
public void addUser(User user) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("INSERT INTO users (id, name) VALUES (?, ?)", user.getId(), user.getName());
}
}
```
在需要切换数据源的时候,通过调用DataSourceContextHolder.setDataSourceKey方法设置当前线程使用的数据源KEY即可。例如:
```java
@GetMapping("/users")
public List<User> getUsers() {
DataSourceContextHolder.setDataSourceKey(DataSourceKey.SLAVE);
return userService.getUsers();
}
```
以上是一个简单的动态切换数据源的示例,可以根据具体需求进行扩展和优化。