You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

H2数据库JdbcSQLNonTransientException异常排查求助

问题原因分析

1. 变量名拼写错误(核心原因)

观察测试代码可以发现:前三个测试方法使用的是сonnector.getConnection()(第一个字母是俄文西里尔字母с),而第四个方法使用的是connector.getConnection()(英文拉丁字母c)。这两个变量名看似相同,实际是不同的标识符。

如果测试类中сonnector是正确注入的H2Connector实例,而connector是未正确初始化、或已被容器销毁的实例,就会导致调用connector.getConnection()时返回已关闭的连接,触发异常。

合并查询到同一方法时用的是正确的сonnector变量,因此能正常获取连接;添加打印语句后,可能触发了变量重新初始化或容器重新注入,使得后续调用能拿到有效连接。

2. 数据库连接资源泄漏

测试方法中只关闭了PreparedStatement,但未关闭Connection。H2嵌入式模式下,未关闭的连接可能导致数据库文件锁定、连接池耗尽或数据库异常关闭,后续获取连接时可能返回已关闭的实例。

解决方法

方法一:统一变量名拼写

将所有测试方法中的连接器变量名统一为同一个(比如全部改为英文的connector),确保使用的是同一个正确注入的H2Connector实例。

方法二:使用try-with-resources自动关闭资源

修改测试代码,用try-with-resources语句自动管理Connection、PreparedStatement和ResultSet的生命周期,避免资源泄漏:

@Test
@DisplayName("Create table in DB")
@Order(1)
public void testCreateTableDB() throws SQLException {
    String testQuery = "CREATE TABLE IF NOT EXISTS test(\n" +
            "     test_id BIGINT AUTO_INCREMENT PRIMARY KEY,\n" +
            "     name VARCHAR(100) NOT NULL\n" +
            ")";

    try (Connection conn = connector.getConnection();
         PreparedStatement statement = conn.prepareStatement(testQuery)) {
        statement.executeUpdate();
    }
}

@Test
@DisplayName("Write to DB")
@Order(2)
public void testWriteDB() throws SQLException {
    String insertQuery = "INSERT INTO test (name) VALUES (?)";

    try (Connection conn = connector.getConnection();
         PreparedStatement insertPreparedStatement = conn.prepareStatement(insertQuery)) {
        insertPreparedStatement.setString(1, "hello from JUnit");
        insertPreparedStatement.executeUpdate();
    }
}

@Test
@DisplayName("Read from DB")
@Order(3)
public void testReadDB() throws SQLException {
    String sql = "SELECT * FROM test WHERE test_id=?";

    try (Connection conn = connector.getConnection();
         PreparedStatement statement = conn.prepareStatement(sql);
         ResultSet rs = statement.executeQuery()) {
        statement.setLong(1, 1);
        while (rs.next()) {
            assertEquals(1, rs.getLong("test_id"));
            assertEquals("hello from JUnit", rs.getString("name"));
        }
    }
}

@Test
@DisplayName("Read data from DB")
@Order(4)
public void testReadActualDB() throws SQLException {
    String sql = "SELECT * FROM clan WHERE clan_id=?";

    try (Connection conn = connector.getConnection();
         PreparedStatement statement = conn.prepareStatement(sql);
         ResultSet rs = statement.executeQuery()) {
        statement.setLong(1, 1);
        while (rs.next()) {
            assertEquals(1, rs.getLong("clan_id"));
            assertEquals("Elfs", rs.getString("name"));
        }
    }
}

方法三:修改H2连接URL参数

在H2的JDBC URL中添加DB_CLOSE_DELAY=-1,防止数据库在最后一个连接关闭时自动关闭,提升连接稳定性:

private final String jdbcURL = "jdbc:h2:~/test;DB_CLOSE_DELAY=-1";

内容的提问来源于stack exchange,提问作者egor-n

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:01:18