很长一段时间没有发技术贴,一方面感觉没什么可以好分享的,另一方面这一段时间主要从事服务端开发工作,发觉以前写的代码是个渣渣。。。
做过接口测试的童鞋应该都了解,假设你们的系统中有支付系统、用户管理系统、商品系统等等,各个系统分别有自己的数据库,这个时候接口校验数据库的时候,需要从多个数据库读取数据,有可能采用的是土方法,分别连接不同数据库去读取数据,我现在分享的也是土方法,不过做了层封装,长的漂亮点而已;PS: 抖音看多了,化妆跟不化妆是神区别

原理

这边简单说下原理,
1.在 spring-jdbc.xml 中设置多个数据数据库的连接信息,然后使用 spring 的 AbstractRoutingDataSource 指定对应的数据库,并使用 defaultTargetDataSource 设置默认数据库
2.这个时候根据写好的自定义注解,在对应的 Mapper 方法,例如查找方法上增加注解,指定要查找某个数据库
3.AOP 切面的方法要在对应的 spring-server.xml 中进行初始化,否则 aop 切面不能正常生效
4.完了,就可以随便找个案例进行测试了

spring-jdbc.xml 配置

DynamicDataSource 实现

package com.finger.test.common;

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


/**
 * Created by 飞狐 on 2018/6/26.
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        System.out.println("DynamicDataSource数据源选择:" + DynamicDataSourceHolder.getDataSource());
        return DynamicDataSourceHolder.getDataSource();
    }
}

DynamicDataSourceHolder 实现

package com.finger.test.common;

/**
 * Created by huqingen on 2018/6/26.
 */
public class DynamicDataSourceHolder {

    public static final ThreadLocal<String> hodler = new ThreadLocal<String>();

    public static void putDataSource(String name){
        hodler.set(name);
    }

    public static String getDataSource(){
        return hodler.get();
    }

    public static void clearHolder(){
        hodler.set(DataSourceConst.LANYA);
    }
}

DataSource 自定义注解

package com.finger.test.common;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by huqingen on 2018/6/26.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value() default DataSourceConst.LANYA;
}

关键玩意,AOP 切面

package com.finger.test.common.net;

import com.finger.test.common.DataSource;
import com.finger.test.common.DataSourceConst;
import com.finger.test.common.DynamicDataSourceHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

/**
 * Created by huqingen on 2018/6/26.
 */
public class DataSourceAspect {

    private Log LOG = LogFactory.getLog(DataSourceAspect.class);

    public Object around(ProceedingJoinPoint point){
        try {
            Object annotation = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(DataSource.class);

            if(annotation == null || !(annotation instanceof DataSource)){
                DynamicDataSourceHolder.putDataSource(DataSourceConst.LANYA);
                LOG.info("现在选择的是:" + DataSourceConst.LANYA );
            } else {
                DynamicDataSourceHolder.putDataSource(((DataSource) annotation).value());
                LOG.info("现在选择的是:" + ((DataSource) annotation).value() );
            }
        } catch (Exception e){
            LOG.error("获取数据源失败",e);
        }

        try {
            Object result = point.proceed();
            DynamicDataSourceHolder.clearHolder();
            return result;
        }catch (Throwable e){
            throw new RuntimeException(e);
        }
    }


}

这个也很关键,得在 spring xml 中配置,初始化的时候生效

测试下


/**
 * Created by 飞狐 on 2018/6/26.
 */
public class DataSourceTest extends BaseSupport{

    @Autowired
    private UserInfoDOMapper userInfoDOMapper;

    @Autowired
    private LYUserInfoDoMapper lyUserInfoDoMapper;

    @Test
    public void test1(){
        //获取蓝芽用户信息
        System.out.println(lyUserInfoDoMapper.selectByPrimaryKey(7300L).getRealName());

        //获取Finger用户信息
        System.out.println(userInfoDOMapper.selectByPrimaryKey(9996L).getUserNick());

    }
}

结束语

写文章不是我擅长的点,比较喜欢直接代码面对面。。。
欢迎各位童鞋多多关注 我们公司产品 Finger,爱好音乐的都可以在上面玩起来


↙↙↙阅读原文可查看相关链接,并与作者交流