SpringMVC+Mybatis之多数据源搭建

(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 holder = new ThreadLocal();
/**
* 设置数据源
* @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。

在这里插入图片描述

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

发布了25 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/sinat_29039125/article/details/94734267
今日推荐