如何在本地模拟丢失的数据库连接?
How to simulate lost database connection locally?
服务器上有一个基于 SpringBoot 的应用程序 运行,它定期 inserts/updates 在关系数据库中记录。
数据库连接是这样设置的:
import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.sql.DataSource;
[...]
@Configuration
@EnableConfigurationProperties
public class DbConfigClass {
[...]
@Bean(name = "myDataSource")
@ConfigurationProperties(prefix = "com.mycompany.somedatabase")
public DataSource dsSomeDataSource() {
return DataSourceBuilder.create().build();
}
[...]
}
有时连接会以不规则、不可预测的间隔中断。然后,我得到这样的错误:
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available,
request timed out after 30001ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:694)
我需要确保我的应用程序可以处理此类中断。为此,我需要能够在本地重现此行为。
我该怎么做?
我查看了 ToxyProxy,这似乎符合我的要求。
但是,我想知道我是否可以更轻松地模拟这种情况,例如。 G。通过使用 Mockito.spy 修改数据源,使其有时会抛出上述异常。
- Mockito 或其他替代方案,因此您必须手动抛出异常
- 使用docker(testcontainers依赖)你可以停止它
- https://www.testcontainers.org/(手动配置)
- https://github.com/Playtika/testcontainers-spring-boot(相对自动,可能不是您现在需要的)
找到一个简单且看似足够好的解决方案:
首先,我创建了一个 class,其 getConnection
方法在每隔两次调用时都会抛出一个异常:
public class ShakyDataSource implements DataSource {
private final DataSource ds;
private AtomicLong getConnectionCallsCount = new AtomicLong(1);
public ShakyDataSource(final DataSource ds) {
this.ds = ds;
}
@Override
public Connection getConnection() throws SQLException {
final long newGetConnectionCallCount = getConnectionCallsCount.incrementAndGet();
if ((newGetConnectionCallCount % 2) == 0) {
throw new SQLException("Simulated connection failure");
}
else {
return ds.getConnection();
}
}
// All other methods of DataSource call corresponding methods of ds
}
然后我修改了这样的配置:
import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.sql.DataSource;
[...]
@Configuration
@EnableConfigurationProperties
public class DbConfigClass {
[...]
@Bean(name = "myDataSource")
@ConfigurationProperties(prefix = "com.mycompany.somedatabase")
public DataSource dsSomeDataSource() {
if (SIMULATE_SHAKY_CONNECTION) {
LOGGER.error("Don't do this in production!");
return new ShakyDataSource(DataSourceBuilder.create().build());
}
return DataSourceBuilder.create().build();
}
[...]
}
服务器上有一个基于 SpringBoot 的应用程序 运行,它定期 inserts/updates 在关系数据库中记录。
数据库连接是这样设置的:
import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.sql.DataSource;
[...]
@Configuration
@EnableConfigurationProperties
public class DbConfigClass {
[...]
@Bean(name = "myDataSource")
@ConfigurationProperties(prefix = "com.mycompany.somedatabase")
public DataSource dsSomeDataSource() {
return DataSourceBuilder.create().build();
}
[...]
}
有时连接会以不规则、不可预测的间隔中断。然后,我得到这样的错误:
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available,
request timed out after 30001ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:694)
我需要确保我的应用程序可以处理此类中断。为此,我需要能够在本地重现此行为。
我该怎么做?
我查看了 ToxyProxy,这似乎符合我的要求。
但是,我想知道我是否可以更轻松地模拟这种情况,例如。 G。通过使用 Mockito.spy 修改数据源,使其有时会抛出上述异常。
- Mockito 或其他替代方案,因此您必须手动抛出异常
- 使用docker(testcontainers依赖)你可以停止它
- https://www.testcontainers.org/(手动配置)
- https://github.com/Playtika/testcontainers-spring-boot(相对自动,可能不是您现在需要的)
找到一个简单且看似足够好的解决方案:
首先,我创建了一个 class,其 getConnection
方法在每隔两次调用时都会抛出一个异常:
public class ShakyDataSource implements DataSource {
private final DataSource ds;
private AtomicLong getConnectionCallsCount = new AtomicLong(1);
public ShakyDataSource(final DataSource ds) {
this.ds = ds;
}
@Override
public Connection getConnection() throws SQLException {
final long newGetConnectionCallCount = getConnectionCallsCount.incrementAndGet();
if ((newGetConnectionCallCount % 2) == 0) {
throw new SQLException("Simulated connection failure");
}
else {
return ds.getConnection();
}
}
// All other methods of DataSource call corresponding methods of ds
}
然后我修改了这样的配置:
import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.sql.DataSource;
[...]
@Configuration
@EnableConfigurationProperties
public class DbConfigClass {
[...]
@Bean(name = "myDataSource")
@ConfigurationProperties(prefix = "com.mycompany.somedatabase")
public DataSource dsSomeDataSource() {
if (SIMULATE_SHAKY_CONNECTION) {
LOGGER.error("Don't do this in production!");
return new ShakyDataSource(DataSourceBuilder.create().build());
}
return DataSourceBuilder.create().build();
}
[...]
}