设置 LOG 后,为什么 h2 在第一次连接时忽略 slf4j 消息?

Why does h2 ignore slf4j messages on the first connection when LOG is set?

请参阅下面的示例代码和输出(标准输出上有 Slf4j/logback)。我找不到任何关于此的错误报告。我正在使用内存模式的 h2 版本 1.3.176(最后稳定版)。为 LOG(0、1 或 2)设置什么值似乎无关紧要,但必须设置。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class H2TraceTest {
    public static void main(String[] args) throws SQLException {
        System.out.println("Query connection 1");
        Connection myConn = DriverManager.getConnection("jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4;LOG=2");
        myConn.createStatement().execute("SELECT 1");

        System.out.println("Query connection 2");
        DriverManager.getConnection("jdbc:h2:mem:tracetest").createStatement().execute("SELECT 1");

        System.out.println("Query connection 1 again");
        myConn.createStatement().execute("SELECT 1");

        System.out.println("End");
    }
}

输出:

Query connection 1
Query connection 2
16:17:02.955 INFO  h2database - jdbc[3] 
/**/Connection conn2 = DriverManager.getConnection("jdbc:h2:mem:tracetest", "", "");
16:17:02.958 DEBUG h2database - jdbc[3] 
/**/Statement stat2 = conn2.createStatement();
16:17:02.959 DEBUG h2database - jdbc[3] 
/**/stat2.execute("SELECT 1");
16:17:02.959 INFO  h2database - jdbc[3] 
/*SQL #:1*/SELECT 1;
Query connection 1 again
End

我知道 H2 documentation 关于 TRACE_LEVEL_FILE 的说法:它影响所有连接。但这不(完全)正确:

每个连接都保留对日志系统的惰性引用。如果您使用特殊标记 TRACE_LEVEL_FILE=4 更改它,那么该引用不会针对所有现有连接进行更改 - 但仅针对那些在该更改后进行首次日志记录的人。

因此,如果您使用连接字符串 "jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4",一切都如预期的那样,因为您的会话在更改日志系统之前不会写入任何日志消息。不幸的是,jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4;LOG=2 中的 LOG=2 首先被评估,因为这两个参数都被写入和读取无序的 Map。并且因为 LOG=2 正在生成日志语句,所以对日志适配器 (=4) 的引用永远不会应用于当前会话。只到下一个。

你能做什么:

  • 仅使用 "jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4" - LOG=2 无论如何都是默认值。如果您需要任何其他日志模式,您可以使用 connection.createStatement().executeUpdate("SET LOG 1")
  • 向连接字符串添加一些默认参数,直到 TRACE_LEVEL_FILE 参数成为映射中的第一个参数(不太可靠,因为顺序可能取决于 VM)
  • 立即放弃第一个连接
  • 填写错误报告并等待修复(或自己修复),因为我认为这是某种错误

我知道这是一个老问题,但这里有一个可靠的方法(即您可以确保先将 TRACE_LEVEL_FILE 设置为 4

String url = "jdbc:h2:mem:tracetest;INIT=SET TRACE_LEVEL_FILE=4\;SET DB_CLOSE_DELAY=-1/* for example, i.e. do other stuff */";