MySQLネスト事務所で発生した問題
3304 ワード
MySQLはネストされたトランザクションをサポートしていますが、そうする人はあまりいません.この間、海外でMySQLのネストされたトランザクションの必要性を議論している外国人を見ました.私を笑わせて、このネストした鬼畜の使い方にはどんなシーンが必要ですか. 以前のdbaの同僚と話したことがありますが、どんなシーンでもMySQLネストされたトランザクションを使用しないでください.
では、MySQLネストトランザクションを使用すると、どのような問題が発生しますか?
前述したように、アーキテクチャ上でトランザクションをネストする人は一般的に少ないが、うっかりネストされることがある.pythonのプロジェクトでは、まず装飾器を使用してトランザクションのパッケージを実現し、データ処理def()と def b()関数はすべてトランザクションにパッケージされ、単純にaとbで大丈夫で、すべて単一トランザクションです. もしa論理でbが呼び出されたら、何が起こるのですか. はい、トランザクションがネストされています... これは数え切れないほどの業務開発に直面する問題だと思います.
では、どのようにしてこのリスクを回避しますか? 鍵をかけてもいいですよ.... グローバルロックを設定し、サブトランザクションが作成される前にロックのステータスを判断します....
flaskのフレームワークの場合、flask gグローバル変数を使用できます.
djangoフレームワークの場合、thread localを使用してグローバル変数を使用できます.
tornado、geventのような非同期ioアーキテクチャであれば、fdを使用してコヒーレント変数の関連付けを行うことができます.
では、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)
最後にrollbackでロールバックしましたが、データは 1 2 3 . 私のトランザクションはネストされた状態だと思っていたが、最後にrollbackがロールバックしたような気がしたが、実際にはサブトランザクションの実行に成功し、外層トランザクションの失敗がロールバックすることを望んでいた. しかし、事実はそうではありません.最後の結果は 1 2 3 .
+-----+
| n |
+-----+
| 1 |
| 2 |
| 3 |
+-----+
sql解釈器がstart transactionに遭遇するとcommitがトリガーされます...!! begin_1 sql_1 begin_2 sql_2 sql_3 commit_1 rollback_1 .
begin_2が実行されたとき、sql_1はすでに提出されており、commitを実行すると1の時、それではsql_2とsql_3提出されました. この时rollbackに行ったら、きっと役に立たないに違いない.... 前に提出したから、何を返してもいいですか.前述したように、アーキテクチャ上でトランザクションをネストする人は一般的に少ないが、うっかりネストされることがある.pythonのプロジェクトでは、まず装飾器を使用してトランザクションのパッケージを実現し、データ処理def()と def b()関数はすべてトランザクションにパッケージされ、単純にaとbで大丈夫で、すべて単一トランザクションです. もしa論理でbが呼び出されたら、何が起こるのですか. はい、トランザクションがネストされています... これは数え切れないほどの業務開発に直面する問題だと思います.
では、どのようにしてこのリスクを回避しますか? 鍵をかけてもいいですよ.... グローバルロックを設定し、サブトランザクションが作成される前にロックのステータスを判断します....
flaskのフレームワークの場合、flask gグローバル変数を使用できます.
djangoフレームワークの場合、thread localを使用してグローバル変数を使用できます.
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