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

Posted

技术标签:

【中文标题】如何使用 JDBC 或 Hibernate 获取当前数据库事务 ID?【英文标题】:How to get the current database transaction id using JDBC or Hibernate? 【发布时间】:2015-07-05 20:05:30 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

甲骨文

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

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

v$transaction 视图提供有关当前正在运行的数据库事务的信息。但是,我们的系统中可以运行多个事务,这就是我们将 v$transactionv$session 视图结合在一起的原因。

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

由于xid 列的类型为RAW,我们使用RAWTOHEX 将事务标识符二进制值转换为其十六进制表示。

Oracle 仅在需要分配撤消段时才分配事务标识符,这意味着已执行 INSERT、UPDATE 或 DELETE DML 语句。

因此,只读事务不会分配事务标识符。

SQL 服务器

使用 SQL Server 时,只需执行以下 SQL 查询:

SELECT CONVERT(VARCHAR, CURRENT_TRANSACTION_ID())

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

PostgreSQL

使用PostgreSQL Server时,可以执行如下SQL查询获取当前事务id:

SELECT CAST(txid_current() AS text)

因为txid_current 函数返回一个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 视图提供有关当前正在运行的数据库事务的信息。由于我们的系统中可以运行多个事务,因此我们需要通过将会话或数据库连接标识符与当前正在运行的会话匹配来过滤事务行。

就像 Oracle 的情况一样,从 MySQL 5.6 开始,只有读写事务才会获得事务标识符。

由于分配事务 id 具有给定的开销,只读事务会跳过此过程。更多详情,请查看this article。

这种只读事务优化在 MariaDB 中的工作方式相同,这意味着事务 id 仅分配给读写事务。

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 允许您注册仅限于当前正在运行的线程的键/值对,并且您可以在日志框架构建日志消息时引用这些键/值对。

要将“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]:%XtxId %c1 - %m%n</Pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

%XtxId 模式用于引用txId 日志变量。

【讨论】:

INNODB_TRX 给出所有活跃的交易。我需要获取当前交易。

以上是关于如何使用 JDBC 或 Hibernate 获取当前数据库事务 ID?的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 Spring 使 JPA(Hibernate)和 JDBC(JdbcTemplate 或 MyBatis)共享同一个事务

Hibernate/H2 外键抛出 org.h2.jdbc.JdbcSQLException

当新记录插入或更新数据库表中的现有记录时,如何 Hazelcast jet JDBC 继续源获取数据?

如何使用 Hibernate 在 MySQL 中获取自增主键值

如何从休眠会话中获取 jdbc 连接? [复制]

PostgreSQL 与 JDBC 或 Hibernate 用于使用 CSV 数据的 Web 应用程序