SHOW TRANSACTION
,但并没有这样的东西。尽职调查:
我查看了其他问题(当然还有事务文档),但没有找到答案。这个问题是关于在连接断开后恢复事务的。这个问题似乎是在问其他线程中是否有活动事务。我想知道的是我的连接是否在事务中。
我也尝试了
SELECT @@AUTOCOMMIT FROM DUAL
,就像这里建议的那样。但是它没有帮助:当我开始一个事务时,它的值不会改变,仍然是1
(“自动提交已启用”)。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)
好的,以前没有,但是现在我有一笔交易,然后...
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)
在innodb_trx中当前的CONNECTION_ID()
仍未有任何内容。
但是,如果我向InnoDB表写入或者只是读取数据...
mysql> SELECT COUNT(1) FROM t1;
+----------+
| COUNT(1) |
+----------+
| 301 |
+----------+
1 row in set (0.00 sec)
现在,我可以看到我的交易记录,因为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)
让我们验证它是否已经消失了...
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 WITH CONSISTENT SNAPSHOT;
Query OK, 0 rows affected (0.00 sec)
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)
...而InnoDB会立即了解该事务。
现在,还有另一种方法来确定你当前是否正在进行事务。或者更正确地说,应该是有另一种方法来确定你当前没有在进行事务。
我将其用于必须在事务中运行的存储过程--调用方负责启动和提交或回滚,如果没有活动事务,该过程将拒绝运行。如何实现呢?
该过程调用另一个过程,如果我有事务,则默默成功,但如果没有,则抛出异常。当一个过程调用第二个过程,并且第二个过程抛出异常时,除非第一个过程安装了HANDLER
来捕获错误,否则第一个过程将以相同的异常终止。
因此,当我的外部过程调用此过程时,如果存在活动事务,则不会发生任何事情,外部过程将被允许运行:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> CALL mysql.require_transaction;
Query OK, 0 rows affected (0.00 sec)
在我的存储过程的开头,我需要做的是只有在被事务调用时才运行。
没有错误,我们正在进行一个事务。如果另一个存储过程调用它,那么该存储过程将仅继续执行下一条指令。
但是,如果我们调用我的 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
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 ;
SAVEPOINT
并立即回滚到它实际上是一个空操作。只要没有已经使用相同名称的活动保存点,就不会有任何影响。我使用了高度不可能的名称 we created to be sure you were in a transaction
来命名我的 SAVEPOINT
。SAVEPOINT
,但这实际上会静默失败。SAVEPOINT
将抛出错误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>
在MySQL 5.1上没有SIGNAL,所以我的require_transaction存储过程只是以本机错误终止,这几乎是有意义的……或者至少足够有意义,以至于有人会向DBA(我)询问它的含义。
为了使其更美观,在MySQL Server 5.5及以上版本中,我们使用CONTINUE HANDLER捕获错误1305,允许我们使用SIGNAL设置自定义错误消息。
设置并立即回滚到保存点是一种悲惨但可靠的确定是否在事务中的方式。
您尝试使用22.31.4 INFORMATION_SCHEMA INNODB_TRX表了吗?
SELECT
COUNT(`trx_id`) `inTransaction?`
FROM
`INFORMATION_SCHEMA`.`INNODB_TRX`
WHERE
`trx_mysql_thread_id` = CONNECTION_ID();
0
。 - undefinedinnodb_trx
表,在我调用START TRANSACTION
之后它仍然完全为空。(虽然我没有对数据库进行任何修改。) - undefined如果像我一样,被诸神诅咒而要处理一个如此古老的遗留系统,它没有innodb_trx
或SIGNAL
,那么下面对Michael-sqlbot的过程进行的改编可能适合你(注意:由于某种原因,它不能是一个函数,必须是一个过程)。
SET @saved_cs_client = @@character_set_client;
SET @saved_cs_results = @@character_set_results;
SET @saved_col_connection = @@collation_connection;
SET character_set_client = utf8;
SET character_set_results = utf8;
SET collation_connection = utf8_general_ci;
SET @saved_sql_mode = @@sql_mode;
SET sql_mode = 'STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ALLOW_INVALID_DATES,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER';
DROP PROCEDURE IF EXISTS `sp_is_in_transaction`;
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_is_in_transaction`(
OUT is_in_transaction TINYINT
)
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION # 1305
BEGIN
SET is_in_transaction = 0 ; # on error realize we are NOT in a transaction
END;
SET is_in_transaction = 1 ;
SAVEPOINT `savepoint_sp_is_in_transaction`;
ROLLBACK TO SAVEPOINT `savepoint_sp_is_in_transaction`;
END $$
DELIMITER ;
SET sql_mode = @saved_sql_mode;
SET character_set_client = @saved_cs_client;
SET character_set_results = @saved_cs_results;
SET collation_connection = @saved_col_connection;
call sp_is_in_transaction( @in_trans );
select @in_trans ;
start transaction ;
call sp_is_in_transaction( @in_trans );
select @in_trans ;
rollback ;
call sp_is_in_transaction( @in_trans );
select @in_trans ;
SAVEPOINT
并回滚到它" 对我的需求来说是一个相当好的解决方案。(也许你应该将其作为一个TL;DNR简介放在顶部 :-)) - undefined