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)
、私のMVCCビューが始動するストレージエンジンを教えていない、後でサーバーを教えて、今
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)
注意を私の孤立したレベルで許可されていない限り、これは実際に私に "一貫性のある"スナップショットを与えません。しかし、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はトランザクションをすぐに知ります。
今、あなたが現在取引中であるかどうかを判断する別の方法があります。または、より正確に言えば、私は今あなたがではないと判断する別の方法があると言うべきです。
これは、トランザクション内で実行する必要があるストアドプロシージャの場合に使用します。呼び出し元は、開始およびコミットまたはロールバックを担当し、アクティブなトランザクションがない場合はプロシージャが実行を拒否します。どうやって?
プロシージャは、トランザクションを持っていればサイレントに成功する別のプロシージャを呼び出しますが、そうでなければ例外をスローします。 1つのプロシージャが2番目のプロシージャをコールし、2番目のプロシージャが例外をスローすると、最初のプロシージャでエラーをキャッチするために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
を作成し、すぐにそれに戻って転がり、本質的に何もしません。同じ名前のアクティブなセーブポイントがない限り、害はなく、ファウルはありません。私はSAVEPOINT
のために非常に起こりそうな名前we created to be sure you were in a transaction
を使用しました。
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>
気の利いたハックだアハハハ。これで、私が私の偽のセーブポイントの名前を使用した理由がわかります。オブジェクト名に「存在しません」というエラーメッセージが追加されます。SIGNAL
を持っていないのMySQL 5.1、オン
、私のrequire_transaction
ストアドプロシージャは、単にほとんど意味のある...または誰かが(私を)DBAを聞いて来ることを十分に少なくとも意味のある、その本来のエラーで終了しますその意味。
MySQL Server 5.5以降では、エラー1305をCONTINUE HANDLER
でキャッチし、SIGNAL
を使用して独自のカスタムエラーメッセージを設定することができます。
セーブポイントを設定してすぐにロールバックするのは、あなたがトランザクション中であるかどうかを判断するうえで、悲劇的だが確かな方法です。
ありがとう! SQLは、対話型の使用や人為的なエラー(ほぼ同じこと)に対応していないだけです。私のユースケースはインタラクティブなコンソールなので、「SAVEPOINTを作成してそれにロールバックしてみてください」というのは、私のニーズにとっては非常に良い解決策です。 (たぶんあなたはTLの一番上にそれを加えるべきでしょう:DNRのイントロ:-) – alexis
私はその提案を勧告のもとで受け取り、答えのリファクタリングを少し考えます。ありがとう。 :) –