mybatis 动态切换 连接对象
时间: 2023-08-13 12:03:46 浏览: 53
在 MyBatis 中,可以通过动态配置来切换连接对象。这个过程通常涉及以下几个步骤:
1. 在 MyBatis 的配置文件中定义多个数据源,例如:
```xml
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.testUrl}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
```
2. 在 MyBatis 的 Mapper 接口中定义多个方法,每个方法对应一个数据源,例如:
```java
public interface UserMapper {
List<User> findAll();
@DataSource("test")
List<User> findTest();
}
```
其中,`@DataSource` 注解指定了使用哪个数据源。
3. 在 MyBatis 的配置文件中添加插件,例如:
```xml
<plugins>
<plugin interceptor="com.example.MybatisPlugin">
<property name="dataSourceNames" value="development,test"/>
</plugin>
</plugins>
```
其中,`MybatisPlugin` 是自定义的插件,用于根据 `@DataSource` 注解切换数据源,`dataSourceNames` 属性指定了所有数据源的名称。
4. 实现自定义插件,例如:
```java
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class })
})
public class MybatisPlugin implements Interceptor {
private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<>();
private List<String> dataSourceNames;
@Override
public Object intercept(Invocation invocation) throws Throwable {
if (invocation.getTarget() instanceof RoutingStatementHandler) {
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
if (sql.toLowerCase().contains("select")) {
String dataSourceName = dataSourceHolder.get();
if (StringUtils.isNotBlank(dataSourceName)) {
Configuration configuration = handler.getConfiguration();
Environment environment = configuration.getEnvironment();
DataSource dataSource = environment.getDataSource();
Connection connection = dataSource.getConnection();
Connection newConnection = dataSource.getConnection();
dataSourceHolder.remove();
return invocation.proceed(new Object[]{newConnection, null});
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
String dataSourceNames = properties.getProperty("dataSourceNames");
if (StringUtils.isNotBlank(dataSourceNames)) {
this.dataSourceNames = Arrays.asList(dataSourceNames.split(","));
}
}
public static void setDataSource(String dataSourceName) {
dataSourceHolder.set(dataSourceName);
}
}
```
其中,`MybatisPlugin` 实现了 `Interceptor` 接口,并且通过 `@Intercepts` 注解指定了拦截 `StatementHandler` 接口的 `prepare` 方法。在拦截方法中,通过 `dataSourceHolder` 保存当前线程要使用的数据源名称,然后调用 `invocation.proceed()` 方法执行下一个拦截器或目标方法。在执行目标方法之前,判断 SQL 是否包含 `select`,如果是,则根据 `dataSourceHolder` 中保存的数据源名称获取对应的数据源,并创建新的连接对象,替换原来的连接对象,以实现切换数据源的效果。
5. 在业务代码中调用 Mapper 方法时,通过 `MybatisPlugin.setDataSource()` 方法设置要使用的数据源名称,例如:
```java
MybatisPlugin.setDataSource("test");
List<User> users = userMapper.findTest();
```