この記事は主に、MySQL のネストされたトランザクションで発生する問題に関する関連情報を紹介します。必要な友人は参照してください。
MySQL はネストされたトランザクションをサポートしていますが、これを行う人は多くありません。少し前に、私は海外にいたときに見ました。外国人の中には、MySQL のネストされたトランザクションの必要性について議論している人もいます。 死ぬほど面白いです。なぜこのシーンにこの入れ子のゴーストの使用が必要なのでしょうか?元 DBA の同僚と話し合ったところ、MySQL のネストされたトランザクションはどのようなシナリオでも使用すべきではないことがわかりました。
では、MySQL のネストされたトランザクションを使用すると、どのような問題が発生するのでしょうか?
mysql> select * from ceshi; +------+ | n | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> start transaction ; Query OK, 0 rows affected (0.00 sec) mysql> insert into ceshi values(2); Query OK, 1 row affected (0.00 sec) mysql> start transaction ; Query OK, 0 rows affected (0.00 sec) mysql> insert into ceshi values(3); Query OK, 1 row affected (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec)
最後にロールバックしましたが、データは 1 2 3 と表示されていました。実際、ロールバックは最終的にロールバックされたように見えますが、実際に確認したい結果は、サブトランザクションが正常に実行され、外側のトランザクションの失敗がロールバックされることです。しかし、これは当てはまらず、最終結果は 1 2 3 です。
+-----+ | n | +-----+ | 1 | | 2 | | 3 | +-----+
SQL インタプリタがトランザクション開始に遭遇すると、コミットがトリガーされます... !!!
begin_1 sql_1 begin_2 sql_2 sql_3 commit_1 rollback_1 .
begin_2 が実行されると, sql_1 すでにサブミットされています。再度 commit_1 を実行すると、sql_2 と sql_3 がサブミットされます。この時点でロールバックを行ってもダメです。すべてが以前にサブミットされているため、何をロールバックできますか。 ..
前に述べたように、アーキテクチャの観点からは、ネストされたトランザクションを使用する人はほとんどいませんが、誤ってネストされてしまうことがあります。 例として Python プロジェクトを取り上げます。まず、デコレーターを使用してトランザクションのパッケージ化を実装します。次に、データ処理関数 def a() と def b() をトランザクションによってラップします。a と b を使用するだけでも問題ありません。単一のトランザクション。ロジックが b を再度呼び出すと、何が起こるでしょうか?はい、トランザクションは入れ子になっています...これは、ほとんどのビジネス開発で遭遇する問題だと思います。
では、このリスクを回避するにはどうすればよいでしょうか? ロックを追加できます...グローバル ロックを設定すると、サブトランザクションが作成される前にロックのステータスが判断されます...
Flask フレームワークの場合、flask g グローバル変数を使用できます。
Django フレームワークの場合、スレッドローカルを使用してグローバル変数を使用できます。
tornado や gevent などの非同期 IO アーキテクチャの場合は、fd を使用してコルーチン変数を関連付けることができます。
@decorator def with_transaction(f, *args, **kwargs): db = connection.get_db_by_table("*") try: db.begin() ret = f(*args, **kwargs) db.commit() except: db.rollback() raise return ret @with_transaction def hide(self): '''订单不在app端显示''' if self.status not in OrderStatus.allow_deletion_statuses(): raise OrderStatusChangeNotAllowed(self.status, OrderStatus.deleted) ... @with_transaction def change_receipt_info(self, address, name, phone): region = Region.get_by_address(address) ...
次のステートメントを実行すると、トランザクションは強制的にコミットされます。 もちろん、ここでの前提は autocommit = True です。
ALTER FUNCTION ALTER PROCEDURE ALTER TABLE BEGIN CREATE DATABASE CREATE FUNCTION CREATE INDEX CREATE PROCEDURE CREATE TABLE DROP DATABASE DROP FUNCTION DROP INDEX DROP PROCEDURE DROP TABLE UNLOCK TABLES LOAD MASTER DATA LOCK TABLES RENAME TABLE TRUNCATE TABLE SET AUTOCOMMIT=1 START TRANSACTION
上記は、MySQL のネストされたトランザクションで発生する問題のコード例の詳細な説明です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。