2016-05-20 21 views
1

有沒有辦法讓MySQL告訴我,如果我當前正在處理事務?我正在從命令行mysql客戶端進行交互式會話,我已經打開並關閉了幾個事務,現在我不應該在事務中,但它的行爲好像我可能是。那麼,如何檢查/驗證我的連接狀態?我試過我的運氣,輸入SHOW TRANSACTION,但沒有這樣的事情。在mysql中顯示當前有效的事務

盡職調查:

我看了其他問題(和transaction documentation,當然),並沒有找到答案。 This question是關於在連接斷開後恢復事務。 This one似乎在詢問在其他線程中是否有事務處於活動狀態。我想查看是否我的連接處於事務中。

我也試過SELECT @@AUTOCOMMIT FROM DUAL,建議here。但它沒有幫助:當我開始一個事務時,它的值不會改變,但仍然是1(「autocommit enabled」)。

回答

1

information_schemainnodb_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) 

現在,告訴服務器來告訴我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 transactionSAVEPOINT

  • 如果您不在事務中,則無法完成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存儲過程簡單地與本地錯誤,這是結束幾乎有意義......或者至少足夠有意義的是,有人來問DB​​A(我)這是什麼意思。

爲了使它更漂亮,在MySQL Server 5.5及更高版本中,我們發現錯誤1305與CONTINUE HANDLER,允許我們使用SIGNAL設置自己的自定義錯誤消息。

設置,然後立即回滾到保存點是一個可悲的方法來確定您是否在交易中。

+1

謝謝! SQL只是不適合交互式使用或人爲錯誤(幾乎相同的事情),是嗎?由於我的用例是交互式控制檯,「嘗試創建一個'SAVEPOINT'並回滾到它」是一個很好的解決方案,可滿足我的需求。 (也許你應該把它作爲TL添加到頂部; DNR簡介:-) – alexis

+0

我會在勸告下采取該建議,並考慮對答案進行一些重構。謝謝。 :) –

1

您是否嘗試使用22.31.4 The INFORMATION_SCHEMA INNODB_TRX Table

SELECT 
    COUNT(`trx_id`) `inTransaction?` 
FROM 
    `INFORMATION_SCHEMA`.`INNODB_TRX` 
WHERE 
    `trx_mysql_thread_id` = CONNECTION_ID(); 
+0

我剛剛做了,並且在開始交易之前和之後它給了我'0'。 – alexis

+0

另外值得注意的是:它需要'PROCESS'特權,所以它並不總是一個選項(即使你可以修復它)。 – alexis

+0

它*看起來像它應該工作,雖然。奇怪。我檢查了'innodb_trx'表,並且在我調用'START TRANSACTION'後它仍然完全是空的。 (儘管我沒有對數據庫進行任何修改。) – alexis