美文网首页
SpringMVC+Mybatis之多数据源搭建

SpringMVC+Mybatis之多数据源搭建

作者: prisoner_mirror | 来源:发表于2020-04-24 15:54 被阅读0次

    (Notice:欢迎交流和沟通,Wx:IT_Ezra,QQ 654303408。仅个人观点和个人理解有问题讨论也可联系我。)

    (PS:写这篇博客的原因是因为刚入行不久,第一次把自己的自己所学的东西应用在实际层面,更让我意识到,基础的重要性。)

    使用场景:当我们的生产数据在逐渐增多,数据库分库分表技能也变得很常见。那么假如说,我们也用户表放到DB1,把订单表放到DB2…等。那么我们查询的时候,要根据不同的数据库去查不同的数据。众所周知,通常一个Mybatis-config.xml里面是配置一个datasource,但是实际上是我们可以配置到多个datasource,然后通过spring-aop来实现。下面直接上干货。

    首先我们要配置mybatis的xml配置文件,当然有不规范的写法,就是把其中的内容直接放到spring的beans.xml文件下也是能够实现的。

    1.datasource的配置,配置多个datasource,根据自己的实际情况而定。

    DataSource

    2.设置多数据源路由。实际上就是一个分发器,就是通过到时候切面的切点值来选择不同的数据库

    多数据源路由

    3 JDBC事务管理。配置jdbc的事务。spring里面也有事务注解来实现DB的事务。

    JDBC事务管理

    4 配置sessionFactory ,以及包扫描

    配置sessionFactory

    5 然后两个工具类以及aop的实现。

    切面接口,DataSourceAspect ,该接口是在service层。也可以实现controller层切

    /**

    • @ author ezra
    • @ date 2019/7/5 11:27
      /
      @Slf4j
      @Aspect
      @Component
      @Order(1) //请注意:这里order一定要小于tx:annotation-driven的order,即先执行DataSourceAspect切面,再执行事务切面,才能获取到最终的数据源
      @EnableAspectJAutoProxy(proxyTargetClass = true)
      public class DataSourceAspect {
      /
      *
     * 切入点 service包及子孙包下的所有类   也可以改为controller级别下的所有
     */
    @Pointcut("execution(* com.dfs.service..*.*(..))")
    public void aspect() {
    }
    /**
     * 配置前置通知,使用在方法aspect()上注册的切入点
     */
    @Before("aspect()")
    public void before(JoinPoint point) {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod() ;
        DataSource dataSource = null ;
        //从类初始化
        dataSource = this.getDataSource(target, method) ;
        //从接口初始化
        if(dataSource == null){
            for (Class<?> clazz : target.getInterfaces()) {
                dataSource = getDataSource(clazz, method);
                if(dataSource != null){
                    break ;//从某个接口中一旦发现注解,不再循环
                }
            }
        }
        if(dataSource != null && !StringUtils.isEmpty(dataSource.value()) ){
            HandleDataSource.setDataSource(dataSource.value());
        }
    }
    @After("aspect()")
    public void after(JoinPoint point) {
        //使用完记得清空
        HandleDataSource.setDataSource(null);
    }
    /**
     * 获取方法或类的注解对象DataSource
     * @param target    类class
     * @param method    方法
     * @return DataSource
     */
    public DataSource getDataSource(Class<?> target, Method method){
        try {
            //1.优先方法注解
            Class<?>[] types = method.getParameterTypes();
            Method m = target.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                return m.getAnnotation(DataSource.class);
            }
            //2.其次类注解
            if (target.isAnnotationPresent(DataSource.class)) {
                return target.getAnnotation(DataSource.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(MessageFormat.format("通过注解切换数据源时发生异常[class={0},method={1}]:"
                    , target.getName(), method.getName()),e)  ;
        }
        return null ;
    }
    

    }

    DataSource 注解接口

    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource {
    String value();
    }

    DataSourceRouter 工具类

    public class DataSourceRouter extends AbstractRoutingDataSource {
    // 获取数据源名称
    protected Object determineCurrentLookupKey() {
    return HandleDataSource.getDataSource();
    }
    }

    HandleDataSource 工具类

    public class HandleDataSource {
    // 数据源名称线程池
    private static final ThreadLocal<String> holder = new ThreadLocal<String>();
    /**
    * 设置数据源
    * @param datasource 数据源名称
    /
    public static void setDataSource(String datasource) {
    holder.set(datasource);
    }
    /
    *
    * 获取数据源
    * @return 数据源名称
    /
    public static String getDataSource() {
    return holder.get();
    }
    /
    *
    * 清空数据源
    */
    public static void clearDataSource() {
    holder.remove();
    }
    }

    在Service添加注解,实现AOP。

    在这里插入图片描述

    所有代码已经实现。通过运行即可。

    相关文章

      网友评论

          本文标题:SpringMVC+Mybatis之多数据源搭建

          本文链接:https://www.haomeiwen.com/subject/pxmhyctx.html