AbstractRoutingDataSource+Mybatis拦截器实现动态切换数据源代码
时间: 2023-12-29 17:44:44 浏览: 192
下面是使用 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);
```
阅读全文