ホームページ  >  記事  >  データベース  >  MySQL のネストされたトランザクションで発生した問題の詳細なコード例

MySQL のネストされたトランザクションで発生した問題の詳細なコード例

黄舟
黄舟オリジナル
2017-03-06 13:26:28975ブラウズ

この記事は主に、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) に注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。