如何在本地模拟丢失的数据库连接?

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 修改数据源,使其有时会抛出上述异常。

找到一个简单且看似足够好的解决方案:

首先,我创建了一个 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();
    }
    
    [...]
}