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)
現在,告訴服務器來告訴我MVCC鑑於從現在開始的存儲引擎,而不是以後:
mysql> START TRANSACTION WITH CONSISTENT SNAPSHOT;
Query OK, 0 rows affected (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)
...和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 ;
這一直是我的什麼,我認爲是在MySQL的設計顯著監督長期的解決辦法 - 顯然未能確定明確,從SQL接口,無論你是在當前交易。這也是爲什麼這個工程:
創建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及更高版本中,我們發現錯誤1305與CONTINUE HANDLER
,允許我們使用SIGNAL
設置自己的自定義錯誤消息。
設置,然後立即回滾到保存點是一個可悲的方法來確定您是否在交易中。
謝謝! SQL只是不適合交互式使用或人爲錯誤(幾乎相同的事情),是嗎?由於我的用例是交互式控制檯,「嘗試創建一個'SAVEPOINT'並回滾到它」是一個很好的解決方案,可滿足我的需求。 (也許你應該把它作爲TL添加到頂部; DNR簡介:-) – alexis
我會在勸告下采取該建議,並考慮對答案進行一些重構。謝謝。 :) –