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(....);
}
我有一个 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(....);
}