Spring 中的双数据库连接?

Dual DB Connectivity in Spring?

我有一个 Web 应用程序,它使用 Oracle 数据库作为后端数据源。这个 Oracle 数据库实例每天都在刷新,在刷新时我们必须无缝切换到另一个数据库(原始数据库的副本),而在另一个数据库(副本)刷新时它应该回退到原始 Oracle 数据库。

我们正在使用 Spring JDBC。

实现此目标的最佳方法是什么?

这在很大程度上取决于您的要求。我会为此使用 Dev-ops。你想要如何获得 Dev-ops 取决于你。每当我看到 Spring 中的切换数据库或重新制作单例 bean 等问题时​​,也只是评论。开发人员总是在做一些非常奇怪的事情,通常是因为他们认为他们有某种需求,但他们真的没有。

有一些 Dev-ops 工具可以提供数据库的只读克隆,可以根据您想要的任何频率从另一个来源进行更新。发生这种情况时无需切换到另一个数据库。 (另请查看模式,其中有许多数据库的只读克隆,以及一个 'true' 数据库,所有写入都重定向到该数据库)

即使这不能满足您的要求,您也可以使用 Dev-ops 可视化端口和数据库 URL 等,并随时随地将其重定向。我也会终止这次跳跃之间的所有会话,但那只是我。

使用 Dev-ops 会将此类内容排除在您的 Spring Web 应用程序的代码之外,因此它保持干净,并且代码不需要随着此要求的变化而更改。处理一个将这些东西硬编码到其中的项目将是令人讨厌的,我建议您谨慎考虑要走的路。如果您确实进行了 Dev-ops,那么您将不会遇到这些问题。

由于管理层未同意 DevOps 相关解决方案,我不得不继续进行基于 AbstractRoutingDataSource 的实施。

解决方案很简单,您只需扩展 AbstractRoutingDataSource 并通过覆盖 determineCurrentLookupKey()[= 提供路由标准28=]方法。

您的自定义数据源将如下所示

public class ResourceAwareMyDataSource extends AbstractRoutingDataSource {

    private static final Logger logger = LoggerFactory.getLogger(ResourceAwareMyDataSource.class);

    @Override
    protected Object determineCurrentLookupKey() {

        try {
            //Check whether the primary DB is active 
            if(primaryIsActive()) {
                return "Primary"
            }
        } catch (Exception e) {
            logger.error("Error occurred when checking  primary",e);
            logger.info("Switching back to Secondary..");
            return "Secondary";
        }
        //Primary is inactive
        logger.info("Primary is Inactive, Switching back to Secondary");
        return "Secondary";
    }
}

这将是您对上述数据源的Java配置

@Bean
@Qualifier("myCustomizedDataSource")
public DataSource resourceAwareMyDataSource() {

    ResourceAwareMyDataSource dataSource = new ResourceAwareMyDataSource ();
    Map<Object, Object> targetDataSourcesMap = new HashedMap();
    targetDataSourcesMap.put("Primary", getPrimaryDataSource());
    targetDataSourcesMap.put("Secondary", getSecondaryDataSource());
    dataSource.setTargetDataSources(targetDataSourcesMap);
    return dataSource;
}

像往常一样,您的主要和次要数据源将如下所示,我在这里提供两个基本数据源以连接到主要和次要

public DataSource getPrimaryDataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(...);
    dataSource.setUrl(...);
    dataSource.setUsername(...);
    dataSource.setPassword(...);
    dataSource.setValidationQuery(...);
    return dataSource;
}

public DataSource getSecondaryDataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(...);
    dataSource.setUrl(...);
    dataSource.setUsername(...);
    dataSource.setPassword(...);
    dataSource.setValidationQuery(....);
}