在 mysql 中显示当前活动的事务

ale*_*xis 2 mysql transactions

有没有办法让 MySQL 告诉我我当前是否在事务中?我在命令行 mysql 客户端的交互式会话中,我打开和关闭了几个事务,现在我不应该在事务中,但它的行为好像我是。那么我如何检查/验证我的连接状态?我碰碰运气并输入了SHOW TRANSACTION,但没有这样的事情。

尽职调查:

我查看了其他问题(当然还有交易文档),但没有找到答案。这个问题是关于在连接断开后恢复事务。似乎是在询问其他线程中是否有活动的事务。我想看看我的连接是否在事务中。

我也尝试过SELECT @@AUTOCOMMIT FROM DUAL,正如这里所建议的那样。但这无济于事:当我开始一个事务时,它的值不会改变而是保持不变1(“启用自动提交”)。

Mic*_*bot 5

information_schema. innodb_trx 告诉你是否在 InnoDB 内的事务中。问题是,如果您还没有访问任何表或显式创建读取快照,那么您只是在MySQL(“服务器层”)的事务中,而不是在 InnoDB(“存储引擎层”)内。

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID();
+----------+
| count(1) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

好吧,我以前没有,但现在我有一个交易,而且……

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID();
+----------+
| count(1) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

...我目前CONNECTION_ID()在 innodb_trx 中仍然没有任何内容。

但是,如果我写入或只是从 InnoDB 表读取...

mysql> SELECT COUNT(1) FROM t1;
+----------+
| COUNT(1) |
+----------+
|      301 |
+----------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

...现在,我可以看到我的事务,因为 InnoDB 知道它。

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID();
+----------+
| count(1) |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

让我们验证它已经消失了......

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID();
+----------+
| count(1) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

现在,告诉服务器告诉存储引擎我的 MVCC 视图现在开始,而不是以后:

mysql> START TRANSACTION WITH CONSISTENT SNAPSHOT;
Query OK, 0 rows affected (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

请注意,除非我的隔离级别允许,否则这实际上并没有给我一个“一致”的快照。但是 InnoDB 现在知道我在这里就足够了。

mysql> SELECT count(1) FROM information_schema.innodb_trx 
    -> WHERE trx_mysql_thread_id = CONNECTION_ID();
+----------+
| count(1) |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

...并且 InnoDB 立即获悉交易。


现在,还有另一种方法可以确定您现在是否在进行交易。或者,更准确地说,我应该说还有另一种方法可以确定您现在不在交易中。

我将它用于必须在事务中运行的存储过程——调用者负责启动和提交或回滚,如果没有活动事务,该过程将拒绝运行。如何?

该过程调用另一个过程,如果我确实有事务,则该过程会默默地成功,但如果我没有,则会引发异常。当一个过程调用第二个过程,而第二个过程抛出异常时,第一个过程会以相同的异常终止,除非第一个过程安装了 aHANDLER来捕获错误。

所以当我的外部过程调用这个过程时,如果有一个事务处于活动状态,什么都不会发生,并且允许外部过程运行:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> CALL mysql.require_transaction;
Query OK, 0 rows affected (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

^^^ 这个 ^^^ 是我在开始时所做的,在我的存储过程中,只有在从事务中调用它们时才需要运行。

没有错误,我们正在进行交易。如果这是另一个调用它的过程,则该过程将继续执行下一条指令。

但是如果我们调用我的require_transaction程序并且我们不在事务中:

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql> CALL mysql.require_transaction;
ERROR 1644 (42000): you must have an active database transaction before attempting
this operation
Run Code Online (Sandbox Code Playgroud)

整洁的。我们使用自定义错误消息使调用方崩溃。如何?

DELIMITER $$
CREATE PROCEDURE `mysql`.`require_transaction`()
BEGIN

-- test the session's transactional status, 
-- throwing an exception if we aren't in a transaction,
-- but finishing successfully if we are

DECLARE CONTINUE HANDLER 
        FOR 1305 
        SIGNAL SQLSTATE '42000' 
        SET MESSAGE_TEXT = 'you must have an active database transaction before attempting this operation';

SAVEPOINT `we created to be sure you were in a transaction`;
ROLLBACK TO SAVEPOINT `we created to be sure you were in a transaction`;

END $$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

这是我长期以来的解决方法,我认为这是 MySQL 设计中的一个重大疏忽——显然无法从 SQL 界面明确确定您当前是否处于事务中。这就是为什么这样做的原因:

  • 创建一个SAVEPOINT并立即回滚到它本质上是一个空操作。只要还没有同名的活动保存点,就没有伤害,没有犯规。我we created to be sure you were in a transaction为我的SAVEPOINT.

  • SAVEPOINT如果您不在事务中,则无法创建 a ,但这实际上以静默方式失败。

  • 回滚到SAVEPOINT不存在的 a 会抛出错误 1305,所以如果你不在事务中,它就没有被创建,现在它不存在,这是你的错误。如果您在事务中,SAVEPOINT则创建然后释放,保持事务原样。

mysql> ROLLBACK TO SAVEPOINT `we created to be sure you were in a transaction`;
ERROR 1305 (42000): SAVEPOINT we created to be sure you were in a transaction does not exist
mysql>
Run Code Online (Sandbox Code Playgroud)

哈哈哈哈这是一个漂亮的黑客。现在你明白为什么我使用我为我的虚假保存点所做的名称——“不存在”被附加到对象名称,以形成错误消息。

在没有 的 MySQL 5.1 上,SIGNAL我的require_transaction存储过程只是以该本地错误终止,这几乎是有意义的……或者至少有意义到有人会来问 DBA(我)这意味着什么。

为了让它更漂亮,在 MySQL Server 5.5 及更高版本中,我们CONTINUE HANDLER使用SIGNAL.

设置然后立即回滚到保存点是一种可悲的骇人听闻的方法,但可以确定您是否处于事务中。