spring-boot多数据源动态切换

时间:2020-01-09
本文章向大家介绍spring-boot多数据源动态切换,主要包括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)、结果:

$flag 上一页 下一页