如何使用 JDBC 或 Hibernate 获取当前数据库事务 ID?

How to get the current database transaction id using JDBC or Hibernate?

为此,我在 Google 上四处寻找,但找不到任何相关内容。基本上,我想掌握 运行 长的交易。

现在,我通过 information_schema.INNODB_TRX 或查看 show engine innodb status 的输出来找到 trx_id,然后打开 general_logs 以查看所有内容查询 运行。

有没有办法,我可以使用 jdbchibernate 在我的代码中获取此 transaction_id,以便我可以将其记录在我的服务器日志中?

甲骨文

使用 Oracle 时,必须执行以下 SQL 查询:

SELECT RAWTOHEX(tx.xid)
FROM v$transaction tx
JOIN v$session s ON tx.ses_addr = s.saddr

v$transaction 视图提供有关当前 运行 数据库事务的信息。但是,我们的系统中可以有多个交易 运行,这就是我们将 v$transaction 加入 v$session 视图的原因。

v$session 视图提供有关我们当前会话或数据库连接的信息。通过匹配v$transactionv$session视图之间的会话地址,我们可以找到v$transaction视图中xid列给出的当前运行交易标识符。

因为 xid 列的类型是 RAW,我们使用 RAWTOHEX 将交易标识符二进制值转换为其十六进制表示形式。

Oracle assigns a transaction identifier only if it needs to assign an undo segment, which implies that an INSERT, UPDATE or DELETE DML statement has been executed.

So, read-only transactions will not have a transaction identifier assigned.

SQL 服务器

使用SQL服务器时,只需执行以下SQL查询:

SELECT CONVERT(VARCHAR, CURRENT_TRANSACTION_ID())

因为 CURRENT_TRANSACTION_ID 函数 returns 一个 BIGINT 列值,我们使用 CONVERT 来获取它的字符串表示形式。

PostgreSQL

当使用 PostgreSQL 服务器时,您可以执行以下 SQL 查询来获取当前事务 ID:

SELECT CAST(txid_current() AS text)

因为 txid_current 函数 returns 一个 BIGINT 列值,我们使用 CAST 来获取它的字符串表示形式。

MySQL 和 MariaDB

当使用MySQL或MariaDB时,您可以执行以下SQL查询来获取当前事务id:

SELECT tx.trx_id
FROM information_schema.innodb_trx tx
WHERE tx.trx_mysql_thread_id = connection_id()

information_schema 目录中的 innodb_trx 视图提供有关当前 运行 数据库事务的信息。由于我们的系统中可以有多个交易 运行,我们需要通过将会话或数据库连接标识符与当前 运行 会话匹配来过滤交易行。

Just like it was the case with Oracle, since MySQL 5.6, only read-write transactions will get a transaction identifier.

Because assigning a transaction id has a given overhead, read-only transactions skip this process. For more details, check out this article.

This read-only transaction optimization works the same way in MariaDB, meaning that a transaction id is only assigned for read-write transactions only.

HSQLDB

当使用 HyperSQL 数据库时,您可以执行以下 SQL 查询来获取当前事务 ID:

VALUES (TRANSACTION_ID())

使用 MDC 记录事务 ID

事务 ID 对于日志记录很有用,因为它允许我们汇总在给定数据库事务的上下文中执行的所有操作。

假设我们已经将上面的SQL查询封装在transactionId方法中,我们可以提取当前事务id并将其作为MDC变量传递给Logger框架。

因此,对于 SLF4J,您可以使用 put 方法,如下例所示:

MDC.put("txId", String.format(" TxId: [%s]", transactionId(entityManager)));

MDC (Mapped Diagnostic Context) 用于记录 ThreadLocal 对 Java 线程的影响。基本上,MDC 允许您注册限制在当前 运行 线程中的 key/value 对,您可以在日志框架构建日志消息时引用它们。

要将“txId”日志变量打印到日志中,我们需要在日志附加程序模式中包含此变量:

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>TRACE</level>
    </filter>
    <encoder>
        <Pattern>%-5p [%t]:%X{txId} %c{1} - %m%n</Pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

%X{txId} 模式用于引用 txId 日志变量。