zoukankan      html  css  js  c++  java
  • spring-boot多数据源动态切换

    当项目中存在多数据源时,就涉及到数据源的动态切换,通过研究,特此记录一下。

    1、maven依赖

    <!--数据库连接-->
    <dependency>
                <groupId>com.oracle</groupId>
                <artifactId>ojdbc6</artifactId>
                <version>11.2.0.4</version>
                <scope>runtime</scope>
            </dependency>
    <!--数据库连接池->
    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
    <!--aop->
    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>

    2、多数据源信息配置

    #多数据源测试
    spring:
      datasource:
        druid:
         master:
            driver-class-name: oracle.jdbc.driver.OracleDriver
            username: test
            password: test
            url: jdbc:oracle:thin:@//ip1:1521/orcl
         slave:
            driver-class-name: oracle.jdbc.driver.OracleDriver
            username: test
            password: test
            url: jdbc:oracle:thin:@//ip2:1521/orcl

    3、数据源配置信息转换成实体类

    @ConfigurationProperties(prefix = "spring.datasource.druid")
    @Data
    @Component
    public class DataSourceProperties {
        private Map<String,String>master;
        private Map<String,String>slave;
    }

    4、动态数据源切换类

    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    
        public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
            super.setDefaultTargetDataSource(defaultTargetDataSource);
            super.setTargetDataSources(targetDataSources);
            super.afterPropertiesSet();
        }
    
    
        @Override
        protected Object determineCurrentLookupKey() {
            return getDataSource();
        }
    
        public static void setDataSource(String dataSource) {
            contextHolder.set(dataSource);
        }
    
        public static String getDataSource() {
            return contextHolder.get();
        }
    
        public static void clearDataSource() {
            contextHolder.remove();
        }
    }

    5、多数据源配置类

    @Configuration
    public class DynamicDataSourceConfig {
    
        @Bean
        public DataSource master(@Autowired DataSourceProperties dataSourceProperties){
            DruidDataSource druidDataSource = new DruidDataSource();
            Map<String, String> master = dataSourceProperties.getMaster();
            druidDataSource.setUsername(master.get("username"));
            druidDataSource.setPassword(master.get("password"));
            druidDataSource.setUrl(master.get("url"));
            //其他参数配置 省略
            return druidDataSource;
        }
    
        @Bean
        public DataSource slave(@Autowired DataSourceProperties dataSourceProperties){
            DruidDataSource druidDataSource = new DruidDataSource();
            Map<String, String> slave = dataSourceProperties.getSlave();
            druidDataSource.setUsername(slave.get("username"));
            druidDataSource.setPassword(slave.get("password"));
            druidDataSource.setUrl(slave.get("url"));
            //其他参数配置 省略
            return druidDataSource;
        }
    
        @Bean
        @Primary
        public DynamicDataSource dataSource(DataSource master,DataSource slave){
            Map<Object,Object>map = new HashMap<>(4);
            map.put("master",master);
            map.put("slave",slave);
            return new DynamicDataSource(master,map);
        }
    }

    6、自定义@DataSource注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource {
    
        String name() default "master";
    }

    7、Aop切面类配置

    @Component
    @Aspect
    public class DataSourceAspect {
    
        @Pointcut("@annotation(com.zxgeo.sso.muiltDatasource.anons.DataSource)")
        public void dataSourcePointCut(){}
    
        @Around(value = "dataSourcePointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
    
            DataSource dataSource = method.getAnnotation(DataSource.class);
            if(dataSource == null){
                DynamicDataSource.setDataSource("master");
            }else {
                DynamicDataSource.setDataSource(dataSource.name());
            }
            try {
                return point.proceed();
            } finally {
                DynamicDataSource.clearDataSource();
            }
        }
    }

    8、启动配置注解信息,重要(不然运行会报错)

    @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})

    9、测试

    (1)、service层(此处没有使用mybatis)

    @Service
    public class TestService {
    
        @Autowired
        private javax.sql.DataSource dataSource;
    
        @DataSource
        public Map<String,Object> getMasterDataSource() throws SQLException {
            Connection connection = dataSource.getConnection();
            Map<String,Object> map;
            try (PreparedStatement preparedStatement
                         = connection.prepareStatement("SELECT *  FROM AA WHERE A=10001")) {
                ResultSet resultSet = preparedStatement.executeQuery();
                map = new HashMap<>();
                while (resultSet.next()){
                    map.put("A",resultSet.getString("A"));
                    map.put("B",resultSet.getString("B"));
                    map.put("C",resultSet.getString("C"));
                }
            }
            return map;
        }
        @DataSource(name = "slave")
        public Map<String,Object> getSlaveDataSource() throws SQLException {
            Connection connection = dataSource.getConnection();
            Map<String,Object> map;
            try (PreparedStatement preparedStatement
                         = connection.prepareStatement("SELECT *  FROM AA WHERE A=10002")) {
                ResultSet resultSet = preparedStatement.executeQuery();
                map = new HashMap<>();
                while (resultSet.next()){
                    map.put("A",resultSet.getString("A"));
                    map.put("B",resultSet.getString("B"));
                    map.put("C",resultSet.getString("C"));
                }
            }
            return map;
        }
    }

    (2)、单元测试

    @SpringBootTest
    @RunWith(SpringRunner.class)
    class SsoApplicationTests {
    
        @Autowired
        private  TestService testService;
    
        @Test
        public void muliDatasorce() throws SQLException {
            Map<String, Object> masterDataSourceUrl = testService.getMasterDataSource();
            System.out.println(masterDataSourceUrl);
            Map<String, Object> slaveDataSourceUrl = testService.getSlaveDataSource();
            System.out.println(slaveDataSourceUrl);
        }
    }

    (3)、结果:

  • 相关阅读:
    (转)Caffe搭建:常见问题解决办法和ubuntu使用中遇到问题(持续更新)
    Ubuntu14.04配置python接口,测试的小问题
    ubuntu简单的小命令
    ubuntu14.04&matlab2015b 测试caffe的Matlab接口
    0427 进制转换
    windows下安装nginx
    事务管理配置与@Transactional注解使用
    spring-web涉及jar包说明
    20145207 《信息安全系统设计基础》第1周学习总结
    《信息安全程序设计基础》第零周学习总结
  • 原文地址:https://www.cnblogs.com/cq-yangzhou/p/12172584.html
Copyright © 2011-2022 走看看