利用AOP编程完成mybatis 动态切换数据源

本文介绍如何在MyBatis中配置多个数据源,并通过AOP实现动态数据源切换,支持不同服务器上的数据库操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mybatis 实现接口和xml的绑定。sql的执行等一系列处理。当我们在使用过程中需要从A服务器数据库查询某张表。B服务器数据库查询另一张表又该怎么做呢?

实现思路

1、配置多个dataSource。

2、设置主从关系

3、定义切面监控所有 mybatis接口。。

4、利用@around注解完成对执行接口类方法的数据源切换。

5、写工具类完成切换



第一步、applicationContext.xml 的基本配置、及mybatis的注册配置

1、我将 jdbc配置文件写在properties 文件内。方便后期管理配置。。采用  库名.Jdbc.字段名的形式。。。 其实怎么弄都可以。。只要自己能看懂。。不引入出错即可。

至于${} 怎么用请自行百度。


<!-- 引入配置文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:spring/properties/jdbc.properties"/>
</bean>
<!--配置A库数据源-->
<bean id="A" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${a.jdbc.driver}"/>
    <property name="url" value="${a.jdbc.url}"/>
    <property name="username" value="${a.jdbc.username}"/>
    <property name="password" value="${a.jdbc.password}"/>
    <!-- 初始化连接大小 -->
    <property name="initialSize" value="${a.jdbc.initialSize}"/>
    <!-- 连接池最大数量 -->
    <property name="maxActive" value="${a.jdbc.maxActive}"/>
    <!-- 连接池最大空闲 -->
    <property name="maxIdle" value="${a.jdbc.maxIdle}"/>
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${a.jdbc.minIdle}"/>
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${a.jdbc.maxWait}"/>
</bean>
<!--配置B库数据源-->
<bean id="B" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${b.jdbc.driver}"/>
    <property name="url" value="${b.jdbc.url}"/>
    <property name="username" value="${b.jdbc.username}"/>
    <property name="password" value="${b.jdbc.password}"/>
    <!-- 初始化连接大小 -->
    <property name="initialSize" value="${b.jdbc.initialSize}"/>
    <!-- 连接池最大数量 -->
    <property name="maxActive" value="${b.jdbc.maxActive}"/>
    <!-- 连接池最大空闲 -->
    <property name="maxIdle" value="${b.jdbc.maxIdle}"/>
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${b.jdbc.minIdle}"/>
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${b.jdbc.maxWait}"/>
</bean>

利用dataSource 设置主从 对数据库进行引用。

<bean id="dataSource" class="self.yzx.util.DynamicDataSource">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <entry value-ref="B" key="B"></entry>
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="A"></property>      <!-- 默认使用A的数据源 -->
</bean>

<!--基于注解的事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--引入dataSource-->
    <property name="dataSource" ref="dataSource"/>
    <!--引入mybatis配置文件-->
    <property name="configLocation" value="classpath:spring/mybatis-config.xml"/>
    <!--下面这句话可以使用可以不使用。如果不使用  默认的xml 寻找模式为对应的接口目录下。即接口和xml必须名称统一,且在同一目录
    此文采用是单独放置其他位置则实现如下配置即可-->
    <property name="mapperLocations" value="classpath:self/yzx/xml/*.xml"/>
</bean>

<!-- 扫描mybatis映射接口类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="self"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

第二步、继承abstractroutingDataSource 重写determineCurrentLookUpkey方法

package self.yzx.util;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDbType();
    }
}

第三步、写切换方法
package self.yzx.util;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDbType(String dbType) {
        contextHolder.set(dbType);
    }

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

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




}
第四步、在接口上添加声明注解
唯独需要修改的就是 接口。。需要 加上注解方便 @around 时候进行判断、这里最好是 直接 定义成 在xml文件里 配置的 数据源名称。。
package self.yzx.itface;

import org.aspectj.lang.annotation.DeclareAnnotation;
import java.util.List;
import java.util.Map;


public interface svlt02 {

    @DeclareAnnotation("A")
    public List<Map<String, Object>> getLog(String msg_ids);

    @DeclareAnnotation("B")
    public List<Map<String, Object>> getCheck(String userName);

}
第五步、利用aop编程实现对接口的监听

execution(* self.yzx.itface.*.*(..))
第一个*代表接受任意形式的返回值
self.yzx.itface 是包。。我把所有的接口当放在 这个目录下
第二个*代表的是接口名称 
第三个*代表的是接口方法
括号里的两个..代表的意思是接受任何形式的参数

及 整句话意思是 self.yzx.itface 目录下 所有 接口 里的任何一个方法 都会被 监听到
返回的obj 就是 mybatis 执行的结果。。

@Aspect
@Component
public class swithDataSourceAspectJ {
    @Around("execution(* self.yzx.itface.*.*(..))")
    public Object process(ProceedingJoinPoint point) throws Throwable {
        //获得目标方法标签
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        //获得目标方法标签里的值
        String sigName = methodSignature.getMethod().getAnnotation(DeclareAnnotation.class).value();
        //切换dataSource
        DataSourceContextHolder.setDbType(sigName);
        //用改变后的参数执行目标方法
        Object obj = point.proceed();
        //清空dataSource 方便下次拦截的时候传入
        DataSourceContextHolder.clearDbType();
        return obj;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值