ale*_*xis 2 mysql transactions
有没有办法让 MySQL 告诉我我当前是否在事务中?我在命令行 mysql 客户端的交互式会话中,我打开和关闭了几个事务,现在我不应该在事务中,但它的行为好像我是。那么我如何检查/验证我的连接状态?我碰碰运气并输入了SHOW TRANSACTION,但没有这样的事情。
尽职调查:
我查看了其他问题(当然还有交易文档),但没有找到答案。这个问题是关于在连接断开后恢复事务。这似乎是在询问其他线程中是否有活动的事务。我想看看我的连接是否在事务中。
我也尝试过SELECT @@AUTOCOMMIT FROM DUAL,正如这里所建议的那样。但这无济于事:当我开始一个事务时,它的值不会改变而是保持不变1(“启用自动提交”)。
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.
设置然后立即回滚到保存点是一种可悲的骇人听闻的方法,但可以确定您是否处于事务中。
| 归档时间: |
|
| 查看次数: |
7642 次 |
| 最近记录: |