SpringBoot如何实现动态数据源?

在Spring Boot中实现动态数据源主要涉及到创建和管理不同的数据源,并在运行时根据需要切换。这可以通过编程方式配置Spring的AbstractRoutingDataSource来完成。下面我会逐步介绍如何实现动态数据源,并给出代码示例。

第1步:添加依赖

首先,你需要在pom.xml文件中添加Spring Boot和数据库相关的依赖。以MySQL为例,你需要添加以下依赖:

<dependencies>
    <!-- Spring Boot Starter Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- MySQL Connector -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

第2步:配置数据源

创建一个配置类来配置多个数据源。首先,定义每个数据源的配置,并使用Spring的@ConfigurationProperties来绑定配置属性。

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("app.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("app.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource());
        targetDataSources.put("slave", slaveDataSource());

        RoutingDataSource routingDataSource = new RoutingDataSource();
        routingDataSource.setDefaultTargetDataSource(masterDataSource());
        routingDataSource.setTargetDataSources(targetDataSources);
        return routingDataSource;
    }
}

第3步:实现AbstractRoutingDataSource

接下来,你需要实现AbstractRoutingDataSource,以便根据当前上下文确定应使用哪个数据源。

public class RoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContext.getCurrentDataSource();
    }
}

第4步:上下文持有器

创建一个DataSourceContext类来持有当前请求的数据源标识。

public class DataSourceContext {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setCurrentDataSource(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getCurrentDataSource() {
        return contextHolder.get();
    }

    public static void clear() {
        contextHolder.remove();
    }
}

第5步:使用切面来切换数据源

你可以使用Spring AOP在方法执行前动态切换数据源。下面是一个示例:

@Aspect
@Component
public class DataSourceAspect {
    @Before("@annotation(targetDataSource)")
    public void switchDataSource(TargetDataSource targetDataSource) {
        DataSourceContext.setCurrentDataSource(targetDataSource.value());
    }

    @After("@annotation(targetDataSource)")
    public void restoreDataSource(TargetDataSource targetDataSource) {
        DataSourceContext.clear();
    }
}

其中TargetDataSource是一个自定义注解,用来在方法上标记需要切换的数据源。

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

第6步:配置application.properties

application.properties中配置你的数据源:

app.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/masterdb
app.datasource.master.username=root
app.datasource.master.password=pass

app.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/slavedb
app.datasource.slave.username=root
app.datasource.slave.password=pass

通过以上步骤,你可以在Spring Boot应用中实现动态数据源,根据不同的需求切换到不同的数据库。这种方式特别适合于读写分离和多租户场景。

7、补充

实际使用中,偏业务的代码往往是根据业务相关ID做计算后放入DataSourceContext数据的,也就是同一个Method,不同的租户/用户使用的数据源可能是不一样的,这才更符合多租户系统的需求。而偏功能的系统,它的Method才有可能是固定的数据源(注解指定)。因此多租户的系统请求过来,我们可以通过在过滤器或者全局拦截器里计算值,然后写数据。

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

济南大飞哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值