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
相关产品推荐
相关产品推荐

