spring - Spring:允许缺少数据库连接
问题描述
我有一个项目连接到多个数据库(Oracle 和 SQLServer),其中一些在启动应用程序时并不总是强制性的,也不可用 - 特别是在开发环境中。
我正在寻找一种方法来允许应用程序在没有数据库连接的情况下启动。我们只需要在执行特定任务时连接到这些数据库,这些任务使用需要特定网络访问的暂存数据库,这在开发人员中并不总是可用。
在这里,使用我们的 Oracle 连接(位于特定网络下的连接):
我们有一个允许应用程序启动的配置,但由于错误的 HikariDataSource 转换,在运行测试时抛出了错误:
@Configuration
@EnableJpaRepositories(
basePackages = "com.bar.foo.repository.oracle",
entityManagerFactoryRef = "oracleEntityManager",
transactionManagerRef = "oracleTransactionManager"
)
public class OracleConfiguration {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Inject
private Environment environment;
@Value("${spring.datasource.oracle.ddl-auto:none}")
private String hibernateddlAuto;
@Value("${spring.datasource.oracle.dialect:org.hibernate.dialect.Oracle10gDialect}")
private String hibernateDialect;
@Bean
@Primary
@ConfigurationProperties("spring.datasource.oracle")
public DataSourceProperties oracleDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource.hikari")
public DataSource oracleDataSource() {
HikariDataSource ds = (HikariDataSource) oracleDataSourceProperties().initializeDataSourceBuilder().build();
ds.setPoolName(environment.getProperty("spring.datasource.oracle.poolName"));
return ds;
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPackagesToScan("com.bar.foo.domain.oracle");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.ddl-auto", hibernateddlAuto);
properties.put("hibernate.dialect", hibernateDialect);
em.setJpaPropertyMap(properties);
em.setDataSource(oracleDataSource());
return em;
}
@Primary
@Bean
public PlatformTransactionManager oracleTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
oracleEntityManager().getObject());
return transactionManager;
}
}
我移动了这个配置来扩展 HikariConfig,如下所示:
@Configuration
@EnableJpaRepositories(
basePackages = "com.bar.foo.repository.oracle",
entityManagerFactoryRef = "oracleEntityManager",
transactionManagerRef = "oracleTransactionManager"
)
@ConfigurationProperties("spring.datasource.oracle")
public class OracleConfiguration extends HikariConfig{
@Bean
@Primary
public DataSource oracleDataSource() {
return new HikariDataSource(this);
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPackagesToScan("com.bar.foo.domain.oracle");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.ddl-auto", hibernateddlAuto);
properties.put("hibernate.dialect", hibernateDialect);
em.setJpaPropertyMap(properties);
em.setDataSource(oracleDataSource());
return em;
}
@Bean
@Primary
public PlatformTransactionManager oracleTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
oracleEntityManager().getObject());
return transactionManager;
}
如果 Oracle DB 不可用,则不会启动。
使用嵌入式数据库不适合我们的用例,因为我们并不总是需要这种连接,而且当我们需要从生产环境复制特定数据时。将其拆分到多个微服务/应用程序上也是不行的,因为这将是一个巨大的重构,并且并不真正适合我们的用例(我们将来自多个来源的数据汇总到一个最终的数据中)。
有没有一种简单的方法可以做到这一点?
解决方案
HikariCP
提供了一些非常不错的配置属性,可能适合您的需求。具体来说(该列表中的第一个)initializationFailTimeout
:
此属性控制如果池无法通过初始连接成功播种,池是否将“快速失败”...
小于零的值将绕过任何初始连接尝试,并且池将在尝试在后台获取连接时立即启动。因此,以后获得连接的努力可能会失败。
如果你想以这种方式解决你的问题,即通过隐藏任何初始化失败(通过设置一个负值initializationFailTimeout
),那么你只需要确保你有正确的逻辑,以防数据库在你得到一个时无法访问/关闭来自池的连接。
推荐阅读
- html - 创建单个元素而不是多个标签
- ios - 在 tableView 和 scrollView 之间连续滚动
- python - 使用 rcParams 更改 matplotlib 网格颜色
- google-apps-script - 对象不允许添加或更改属性 - 可安装的编辑触发器
- android - 一些参数被插入到 Firebase 实时数据库 Android Studio
- angular - 如果在 ngFor 中使用,如何获取 mat-checkbox 检查值
- node.js - 如何使用 parseInt() 函数将字符串转换为 bigint
- haskell - 在 Pipes 库中使用请求和响应进行双向通信
- python - 如何使用 ezdxf 查找镜像实体(如块/圆)的位置?
- html - 在 html 的 li 标记的不同侧制作文本