zoukankan      html  css  js  c++  java
  • Springboot+Mybatis AOP注解动态切换数据源

    在开发中因需求在项目中需要实现多数据源(虽然项目框架是SpringCloud,但是因其中只是单独的查询操作,觉得没必要开发一个项目,所以采用多数据源来进行实现)

    1.在配置文件中创建多个数据连接配置

    spring.datasource.primary.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.primary.url=jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false
    spring.datasource.primary.username=root
    spring.datasource.primary.password=root
    spring.datasource.primary.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.primary.max-wait=10000
    spring.datasource.primary.max-idle=8
    spring.datasource.primary.min-idle=8
    spring.datasource.primary.initial-size=10
    spring.datasource.primary.max-active=20
    spring.datasource.primary.test-on-borrow=true
    spring.datasource.primary.test-while-idle=true
    spring.datasource.primary.validation-query=SELECT 1 FROM DUAL
    spring.datasource.primary.time-between-eviction-runs-millis=300000
    spring.datasource.primary.min-evictable-idle-time-millis=1800000
    
    
    spring.datasource.second.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.second.url=jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false
    spring.datasource.second.username=root
    spring.datasource.second.password=root
    spring.datasource.second.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.second.max-wait=10000
    spring.datasource.second.max-idle=8
    spring.datasource.second.min-idle=8
    spring.datasource.second.initial-size=10
    spring.datasource.second.max-active=20
    spring.datasource.second.test-on-borrow=true
    spring.datasource.second.test-while-idle=true
    spring.datasource.second.validation-query=SELECT 1 FROM DUAL
    spring.datasource.second.time-between-eviction-runs-millis=300000
    spring.datasource.second.min-evictable-idle-time-millis=1800000

     2.配置完成后需要创建数据源的连接工厂

     2.1第一个数据源连接配置

    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    @Configuration
    //配置mybatis的接口类放的地方
    @MapperScan(basePackages = "com.cloud.demo.dao.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
    public class DataSourceFirstConfig {
        // 将这个对象放入Spring容器中
        @Bean(name = "primaryDataSource")
        // 表示这个数据源是默认数据源
        @Primary
        // 读取application.properties中的配置参数映射成为一个对象
        // prefix表示参数的前缀
        @ConfigurationProperties(prefix = "spring.datasource.primary")
        public DataSource getDateSource1() {
            return DataSourceBuilder.create().build();
        }
        @Bean(name = "primarySqlSessionFactory")
        // 表示这个数据源是默认数据源
        @Primary
        // @Qualifier表示查找Spring容器中名字为test1DataSource的对象
        public SqlSessionFactory test1SqlSessionFactory(@Qualifier("primaryDataSource") DataSource datasource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(datasource);
            bean.setMapperLocations(
                    // 设置mybatis的xml所在位置
                    new PathMatchingResourcePatternResolver().getResources("classpath*:com/cloud/demo/mapping/primary/*.xml"));
            return bean.getObject();
        }
        @Bean("primarySqlSessionTemplate")
        // 表示这个数据源是默认数据源
        @Primary
        public SqlSessionTemplate test1sqlsessiontemplate(
                @Qualifier("primarySqlSessionFactory") SqlSessionFactory sessionfactory) {
            return new SqlSessionTemplate(sessionfactory);
        }
    }

      2.2第二个数据源配连接配置

    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    @Configuration
    @MapperScan(basePackages = "com.cloud.demo.dao.second", sqlSessionFactoryRef = "secondSqlSessionFactory")
    public class DataSourceSecondConfig {
        @Bean(name = "secondDataSource")
        @ConfigurationProperties(prefix = "spring.datasource.second")
        public DataSource getDateSource2() {
            return DataSourceBuilder.create().build();
        }
        @Bean(name = "secondSqlSessionFactory")
        public SqlSessionFactory test2SqlSessionFactory(@Qualifier("secondDataSource") DataSource datasource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(datasource);
            bean.setMapperLocations(
                    new PathMatchingResourcePatternResolver().getResources("classpath*:com/cloud/demo/mapping/second/*.xml"));
            return bean.getObject();
        }
        @Bean("secondSqlSessionTemplate")
        public SqlSessionTemplate test2sqlsessiontemplate(
                @Qualifier("secondSqlSessionFactory") SqlSessionFactory sessionfactory) {
            return new SqlSessionTemplate(sessionfactory);
        }
    }

    PS: @Primary注解一定要配置,否则不知道哪个是默认数据源配置

    3.保存切换数据源

    public class DataSourceContextHolder {
        
        //默认数据源
        public static final String DEFAULT_DS = "primaryDataSource";
     
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
     
        // 设置数据源名
        public static void setDB(String dbType) {
            System.out.println("切换到{"+dbType+"}数据源");
            contextHolder.set(dbType);
        }
     
        // 获取数据源名
        public static String getDB() {
            return (contextHolder.get());
        }
     
        // 清除数据源名
        public static void clearDB() {
            contextHolder.remove();
        }
    }

    4.当前数据源

    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
            System.out.println("数据源为"+DataSourceContextHolder.getDB());
            return DataSourceContextHolder.getDB();
        }
    
    }

    5.创建自定义注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface DataSource {
        String value() default "primaryDataSource";
    }

    6.使用AOP创建切点

    import java.lang.reflect.Method;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class DynamicDataSourceAspect {
        @Before("@annotation(DataSource)")
        public void beforeSwitchDS(JoinPoint point){
            //获得当前访问的class
            Class<?> className = point.getTarget().getClass();
            //获得访问的方法名
            String methodName = point.getSignature().getName();
            //得到方法的参数的类型
            Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
            String dataSource = DataSourceContextHolder.DEFAULT_DS;
            try {
                // 得到访问的方法对象
                Method method = className.getMethod(methodName, argClass);
                // 判断是否存在@DS注解
                if (method.isAnnotationPresent(DataSource.class)) {
                    DataSource annotation = method.getAnnotation(DataSource.class);
                    // 取出注解中的数据源名
                    dataSource = annotation.value();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 切换数据源
            DataSourceContextHolder.setDB(dataSource);
        }
        
        @After("@annotation(DataSource)")
        public void afterSwitchDS(JoinPoint point){
            DataSourceContextHolder.clearDB();
        }
    }

    7.启动类修改:


    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @MapperScan(basePackages
    = {"com.cloud.demo.*.dao"})public class TrusteeInterfaceApplication { public static void main(String[] args) { SpringApplication.run(TrusteeInterfaceApplication.class, args); } }

    8.使用方式

    只需要在service的实现类中的方法上方使用注解即可

    @Override
    @DataSource("primaryDataSource")
    public void saveTGLsbrkjg(TgLsbrkjg tgLsbrkjg) {
        tableMapper.saveTg(tgLsbrkjg);
    }
  • 相关阅读:
    Ros与Vrep平台搭建
    场景采集难点
    写给师弟师妹论文排版秘籍
    采集项目笔记2
    采集项目记录1
    NLP&Python笔记——nltk模块基础操作
    Hash算法(含python实现)
    Python学习笔记——Socket通信
    Python学习笔记——GIF倒放处理
    OSError: [WinError 126] 找不到指定的模块 —— 解决办法
  • 原文地址:https://www.cnblogs.com/guanjunhui/p/10951480.html
Copyright © 2011-2022 走看看