はじめに:
トランザクション ( Transaction
) は、一連の SQL から構成される実行単位 (Unit) であり、データベースの同時実行制御およびリカバリ ロールバックの基本単位です。トランザクションには複数の SQL が含まれる場合があり、すべてが失敗するか、すべてが成功するかのいずれかになります。
目次
1. 取引の起源
ほとんどのプログラマーにとって、彼らの仕事は現実世界のビジネス シナリオをデータベースの世界にマッピングすることです。たとえば、銀行は人々の口座情報を保存するテーブルを作成しますaccount
。
mysql> CREATE TABLE account (
id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',
name VARCHAR(100) COMMENT '客户名称',
balance INT COMMENT '余额',
PRIMARY KEY (id)
);
Query OK, 0 rows affected (0.04 sec)
Zhang San と Li Si は仲が良く、二人で銀行に口座を開設しに行くと、現実世界で所有する資産がデータベース世界の口座テーブルに反映されます。たとえば、現在、Zhang San は 11 元を持っていますが、Li Si は 2 元しか持っていないため、この状況は実際には次のようにデータベースのアカウント テーブルにマッピングされます。
mysql> INSERT INTO account(name,balance) VALUES ('张三',11),('李四',2);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 11 |
| 2 | 李四 | 2 |
+----+--------+---------+
2 rows in set (0.00 sec)
特定の瞬間に、銀行の Zhang San Li Si のような人物が所有する資産には特定の価値があり、これらの特定の値は、この特定の瞬間における現実世界の口座の状態として説明することもできます。時間が経つと、張三と李斯は口座にお金を預けたり、お金を引き出したり、他の人にお金を送金したりするなどの操作を連続して実行するため、口座の残高が変化する可能性があり、それぞれの操作は口座に相当します。現実世界では状態遷移です。現実世界のマッピングとして、データベースの世界も当然、それに対応して変化する必要があります。変化しないと分からない、変化するとびっくりする、現実世界での一見単純な状態遷移をデータベースの世界にマッピングするのはそれほど簡単ではありません。たとえば、あるとき、リー・シーが10元が必要になり、10元を借りるために急いでチャン・サンに電話したとき、現実世界では、チャン・サンはATMまで歩いて行き、リー・シーの口座番号と10元の送金金額を入力して、確認しましたと押すと、チャン・サンはカードを取り出して立ち去りました。データベースの世界では、これは次の 2 つのステートメントを実行するのと同じです。
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> UPDATE account SET balance = balance + 10 WHERE id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
しかし、ここで問題が発生します。上記の 2 つのステートメントのいずれか 1 つだけが実行されたときにサーバーの電源が突然切れた場合はどうすればよいでしょうか? 張三のお金は差し引かれましたが、李斯には送金しませんでした~ たとえ1つの声明であっても、Buffer Pool
特定のページに読み書きアクセスするときは、Buffer Pool
将来的には最初にこのページをロードするだろうと私たちが小言を言ったときに前に言いました。後でページが変更された場合、その変更はすぐにはディスクに同期されませんが、変更されたページのみがBuffer Pool
リンクリストに追加され、flush
後の時点でディスクに更新されます。変更されたページがディスクにフラッシュされる前にシステムがクラッシュした場合、Li Si にはまだお金がないのではありませんか? それとも、ディスクをリフレッシュしている途中 (データの一部のみがディスクにリフレッシュされます) でシステムがクラッシュし、Li Si にお金がなくなってしまいましたか?
貧しい李斯が確実に金持ちになるにはどうすればよいでしょうか? 実際、よく考えてみると、データベース操作の一部を、現実世界の状態遷移のルールに合わせたいだけなのですが、データベースを設計したおじさんたちは、綿密に計算して計算してきたのです。現実世界、ゆっくり見ていきましょう。
1.1 原子性
現実の世界では、転送操作は分離できない操作です。つまり、転送がまったく行われないか、転送が成功するかのいずれかであり、中間状態、つまり転送の半分が存在することはできません。データベースを設計するとき、この要么全做,要么全不做
種のルールを と呼びます原子性
。ただし、現実の世界では分離できない操作が、データベースの世界ではいくつかの異なる操作に対応する場合があり、データベースの操作はいくつかのステップに分解される場合もあります (最初にキャッシュ ページを変更し、次にそれをディスクにリフレッシュするなど)。 .)、最も恐ろしいのは、予期しないエラーがいつでも発生する可能性があり (データベース自体のエラー、オペレーティング システムのエラー、さらには直接的な電源障害など)、操作を続行できなくなることです。だから李四もお金を持っているかもしれない。データベースの世界で特定の操作のアトミック性を確保するには、データベースの設計時にある程度の労力を費やして、操作の実行中にエラーが発生した場合に、実行された操作が元の状態に復元されるようにする必要があります。実行前の状態については、次の章で詳しく説明します。
1.2 隔離
現実世界における 2 つの状態遷移は相互に影響を与えるべきではありません。たとえば、Zhang San と Li Si は 5 元の送金を 2 つ同時に行います (2 つの ATM で同時に操作できると仮定します)。すると最終的には、張三の口座は確実に10元減り、李斯の口座は確実に10元増えることになる。しかし、対応するデータベースの世界では、状況はもう少し複雑になります。問題を単純化するために、Zhang San が Li Si に 5 元を送金するプロセスは次の手順で構成されると大まかに仮定します。
- ステップ 1: Zhang San の口座の残高を変数 A に読み取ります。このステップは次のように省略されます。
read(A)
- ステップ 2: Zhang San の口座残高から送金金額を差し引きます。このステップは次のように省略されます。
A = A - 5
- ステップ 3: Zhang San のアカウントの変更された残高をディスクに書き込みます。このステップは次のように省略されます。
write(A)
- ステップ 4: Li Si の口座残高を変数 B に読み取ります。このステップは次のように省略されます。
read(B)
- ステップ 5: Li Si の口座の残高を送金金額に追加します。このステップは次のように省略されます。
B = B + 5
- ステップ 6: Li Si のアカウントの変更された残高をディスクに書き込みます。このステップは次のように省略されます。
write(B)
T1
Zhang San から Li Si への 2 つの同時転送操作をそれぞれ合計と呼びますT2
。現実の世界では、T1
合計T2
はそれとは何の関係もありません。最初にT1
実行してから実行することT2
も、最初に実行してT2
から実行することもできますT1
。対応するデータベース操作は次のようになります。
しかし、残念なことに、実際のデータベースでの操作は、次のように交互に実行されるT1
可能性があります。T2
上図の実行順序に従って2回送金すると、6
最終的に張三の口座には元が差し引かれるだけの人民元が残ります5
が、李斯の口座にはさらに元銭12
に相当する人民元が残ります。 10
、この銀行は損をするのではないか?
したがって、現実世界の状態遷移に対応する一部のデータベース操作では、これらの操作が原子性
特定の方法で完了することを保証するだけでなく、他の状態遷移がこの状態遷移に影響を与えないことも保証する必要があります。と呼ばれる隔离性
。このとき、データベースを設計するおじさんは、同じデータ(上記のAアカウントとBアカウント)にアクセスする異なる状態遷移(上記の例ではT1とT2)に対応したデータベース操作の実行順序を工夫する必要があります。例) 一定の順序がある規則性、これについては次の章で説明します。
1.3 一貫性
私たちが住む世界には、ID番号は重複できない、性別は男性か女性のみ、大学入試の得点は0点から750点までしかできないなど、さまざまな制約があります。人民元の単位は 100 人民元まで、信号機は 3 種類しかありません、色、家の価格はマイナスであってはなりません、生徒は先生の言うことを聞くべきです、なんとか、なんとか、何とか、なんとか、なんとか彼がナンセンスを話していることがわかります。データベースの世界は現実世界をマッピングしたものにすぎず、現実世界に存在する制約は当然データベースの世界にも反映されなければなりません。データベース内のすべてのデータが現実世界の制約 (定義されたすべてのルール) に準拠している場合、データは一貫している、または一貫していると言えます。
データベース内のデータの一貫性を確保する (つまり、現実世界のすべての制約に準拠する) にはどうすればよいでしょうか? これは実際には次の 2 つの取り組みに依存しています。
側面 1:データベース自体は、一部の一貫性要件を保証できます (つまり、データベース自体は、現実世界の制約が常に有効であることを保証できます)。
MySQL データベースは、値の挿入を拒否するために列をテーブルとして作成し、宣言できる主键
ことがわかっています。たとえば、特定のカラムに一意のインデックスを作成する場合、特定のレコードの挿入時にカラムの値が繰り返されると、MySQL はエラーを報告し、挿入を拒否します。私たちがすでによく知っている一貫性を保証するこれらの機能に加えて、MySQL は次のような制約を定義するための CHECK 構文もサポートしています。唯一索引
外键
NOT NULL
NULL
CREATE TABLE account (
id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',
name VARCHAR(100) COMMENT '客户名称',
balance INT COMMENT '余额',
PRIMARY KEY (id),
CHECK (balance >= 0)
);
上記の例のステートメントの本来の目的は、列に より小さい数値を格納できないことCHECK
を規定することであり、実際の対応する意味は、銀行口座残高を より小さくすることはできないということです。しかし、残念ながら、つまり、上記の句を含むテーブル構築ステートメントを使用してテーブルを作成したとしても、MySQL はレコードの挿入または更新時に CHECK 句の制約が確立されているかどうかをチェックしません。balance
0
0
MySQL仅仅支持 CHECK语法,但实际上并没有一点卵用
CHECK
account
小提示:
SQL Server や Oracle でサポートされている CHECK 構文など、他のデータベースには実際の効果があります。レコードを挿入または更新する前に、データが CHECK 句で指定された制約を満たしているかどうかがチェックされます。そうでない場合は、挿入または更新が行われます。拒否されます。
句は整合性チェックには役に立ちませんがCHECK
、トリガーを定義することでいくつかの制約を定義し、データベース内のデータの整合性を確保できます。
側面 2:ビジネス コードを作成するプログラマーは、より多くの一貫性要件を保証する必要があります。
現実世界とデータベース世界の対応関係を確立するには、理論的には現実世界のすべての制約がデータベース世界に反映されるはずですが、残念ながら、データベースを変更するときに整合性チェックを実行するのはパフォーマンスを重視する作業です。データ (
例account
: テーブルのトリガーを作成しました。レコードが挿入または更新されるたびに、balance
列挿入または更新の速度に影響します)。レコードの行が一貫性要件を満たしていないことを確認するだけでは、大きな問題はありません。一部の一貫性要件は単に異常です。たとえば、銀行は、各口座のすべての取引を記録する請求書を表すテーブルを作成します。每一笔交易完成后,都需要保证整个系统的余额等于所有账户的收入减去所有账户的支出
。この一貫性要件がデータベース レベルで実装されている場合、トランザクションが発生するたびに、すべての収入を合計してすべての支出を差し引き、すべての口座残高を合計して 2 つの値が等しくないかどうかを確認する必要があります。これはおかしいと思いませんか? 請求書テーブルに数億件のレコードがある場合、検証プロセスだけで数時間かかる場合があります。つまり、パンケーキ スタンドでパンケーキを購入すると、購入後数時間待たなければなりません。銀行カードで支払う場合、支払いが成功したことを通知するまでに何時間もかかり、そのようなパフォーマンス コストはまったく支払えません。
現実には複雑な一貫性要件がたくさんありますが、パフォーマンスの問題のため、一貫性要件をデータベースに引き渡すのは非現実的であるため、この問題はビジネス側のプログラマに投げかけられます。たとえば、このテーブルの場合、ビジネスを作成するプログラマーが、操作によって列の値が 0 未満の値に更新されるaccount
タイミングを独自のビジネス コードで判断する限り、トリガーを作成する必要はありません。balance
実行されませんが、問題なく動作するはずです。
私たちがこれまでしつこく主張してきたこと原子性
、そしてそれに影響を隔离性
与えることになるもの一致性
たとえば、現実世界での送金操作が完了した後、一致性
送金に参加しているアカウントの合計残高が変更されないという要件があります。データベースが要件に従っていない場合原子性
、つまり、送金の半分が経過しても送金されない場合、つまり、お金は Zhang San から差し引かれるが、Li Si には送金されない場合、データベースは次の要件を満たしていません一致性
。同様に、データベースが隔离性
要件に従っていない場合は、先ほどの小言の例で述べたように隔离性
、Zhang San の口座から引き落とされるお金は、Li Si の口座で増えたお金とは異なる可能性があります。ニーズを満たしていないということです一致性
。つまり、数据库某些操作的原子性和隔离性都是保证一致性的一种手段,在操作执行完成后保证符合所有既定的约束则是一种结果
。和を満たす演算原子性
を満たさなけれ隔离性
ばならないのでしょうか一致性
?それは必ずしも真実ではありません。たとえば、張三は李斯に 20 元を送金したいと考えています。彼は満足していますが、原子性
送金隔离性
が完了すると張三の口座の残高はマイナスになります。これは明らかに満足のいくものではありません一致性
。原子性
和を満たさない操作は隔离性
必ずしも満足できないものなのでしょうか一致性
? これは必ずしも当てはまるわけではありません。最終結果が現実世界のすべての制約に準拠している限り、準拠しています一致性
。
1.4 耐久性
現実世界の状態遷移が完了すると、その遷移結果が永続的に保持されるルールで、データベースを設計したおじさんたちが呼び出します持久性
。たとえば、Zhang San が Li Si に送金する場合、ATM が送金が成功したことを示すメッセージを表示すると、口座ステータスの移行が完了したことになり、Zhang San はカードを引き出して去ることができます。張三が去った後、銀行が送金操作をキャンセルして送金前の状態に戻った場合、李斯にはまだお金がないため、これは非常に持久性
重要です。永続性とは、現実世界の状態遷移をデータベース世界にマッピングする際、その遷移に対応するデータベース操作によって変更されたデータがディスク上に保持されることを意味し、事故後に何が起こっても、この遷移の影響は影響を受けないことを意味します。失われるべきです。
2. 事業の考え方
上で述べた現実世界の状態の遷移過程で観察すべき4つの特徴を誰もが覚えやすいように、これら4つの単語に対応する英単語の頭文字、 、 、およびこれらを抽出原子性(Atomicity)
し隔离性(Isolation)
ます一致性(Consistency)
。 4 つの単語、順序を少し変更して、次の完全な英単語を形成します。おそらく誰もが中学や高校で英語を習ったことがあると思いますが、ACIDとは英語で酸を意味しますが、今後ACIDという言葉を聞くとき、誰もが原子性、一貫性、分離性、永続性の法則を思い浮かべるはずです。なお、データベースを設計したおじさんは便宜上、保証が必要な1つ以上のデータベース操作を、、と1 つと呼んでいました(英語名は)。持久性(Durability)
A、I、C、D
ACID
原子性
隔离性
一致性
持久性
事务
transaction
これは抽象的な概念であり、実際には 1 つ以上のデータベース操作に対応していることがわかりました。データベースを設計したおじさんは、データベース事务
を操作のさまざまな段階に応じて事务
次の状態に大まかに分類しました。
-
アクティブな (アクティブな)トランザクション
に対応するデータベース操作が実行されているとき、そのトランザクションは進行中であると言います活动的状态
。 -
部分的にコミットされた (部分的にコミットされた)
トランザクション内の最後の操作が実行されたが、操作はメモリ内で実行されるため、その影響はディスクにフラッシュされず、トランザクションが進行中であるといいます部分提交的状态
。 -
失敗 (failed)
トランザクションがアクティブまたは部分的にコミットされた状態にある場合、何らかのエラー (データベース エラー、オペレーティング システム エラー、または直接電源障害など) が発生し、実行を続行できないか、現在のトランザクションを人為的に停止する可能性があります。トランザクションの実行を、トランザクションが にあると言います失败的状态
。 -
中止(中止)先ほど
小言を言っ失败的状态
た張三から李斯への送金取引のように、張三の口座のお金は引き落とされたが、李斯の口座のお金が増えなかった場合、取引が途中で実行された場合、エラーとなります。現在のトランザクションが実行されるようにするには失败的状态
、Zhang San の変更されたアカウント残高を転送前の金額に調整する必要があります。つまり、現在のデータベースに対する失敗したトランザクションの影響をキャンセルする必要があります。 。書面では、このプロセスを 失効 と呼びます回滚
。操作が完了したとき回滚
、つまりデータベースがトランザクション実行前の状態に復元されたとき、トランザクションは進行中であると言います中止的状态
。 -
コミット済み (コミット済み)
部分的にコミットされた状態のトランザクションが、変更されたすべてのデータをディスクに同期すると、トランザクションは適切な状態にあると言えます提交的状态
。
トランザクションに対応するデータベース操作がさまざまな段階で実行されるため、トランザクションの状態も変化します。基本的な状態遷移図は次のとおりです。
図からもわかるように只有当事务处于提交的或者中止的状态时,一个事务的生命周期才算是结束了
、 。コミットされたトランザクションの場合、トランザクションによってデータベースに加えられた変更は永続的に有効になり、中止された状態のトランザクションの場合、トランザクションによってデータベースに加えられたすべての変更は前の状態にロールバックされます。トランザクションが実行されました。
小提示:
私たちのコンピュータ用語は基本的に英語から中国語に翻訳されていることは誰もが知っています。事務の英語はtransaction、英語の直訳は取引を意味します。売買の意味は、買い手が支払い、売り手が商品を引き渡すことです。配達はありません。納品後の支払いはありません。そのため、取引自体は切り離せない作業です。どの偉い神がtransactionをtransactionと訳したのかは分かりません(これ以上良い言葉が思いつかないので、ランダムに見つけるしかないのだと思います)transactionという言葉には取引や販売の意味は全くありませんので、誰にとっても理解が難しくなりますが、外国人の方が取引を理解できるかもしれません~
3. MySQL のトランザクションの構文
トランザクションの本質は実際には一連のデータベース操作であると言われますが、これらのデータベース操作はACID
特性に準拠しています。では、特定の操作をトランザクションに入れて MySQL で実行するにはどうすればよいでしょうか? 次は小言に焦点を当てましょう。
3.1 トランザクションの開始
次の 2 つのステートメントのいずれかを使用して、トランザクションを開始できます。
ステートメント 1: BEGIN [WORK];
BEGIN
このステートメントはトランザクションの開始を表し、次の単語はWORK
オプションです。トランザクションを開始した後、開始したばかりのトランザクションに属する複数のステートメントを書き続けることができます。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> 加入事务的语句...
ステートメント 2: START TRANSACTION;
START TRANSACTION
ステートメントとBEGIN
ステートメントは同じ効果があり、どちらも次のようにトランザクションの開始を示します。
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> 加入事务的语句...
しかし、BEGIN
ステートメントよりももう少し強力なのはSTART TRANSACTION
、ステートメントの後にいくつかの修飾子を付けることができるということです。そのうちのほんの一部を次に示します。
-
READ ONLY
: 現在のトランザクションが読み取り専用トランザクションであることを示します。つまり、このトランザクションに属するデータベース操作はデータの読み取りのみが可能で、データの変更はできません。小提示:
実際、読み取り専用トランザクションは、他のトランザクションもアクセスできるテーブル内のデータを変更することのみが許可されています。一時テーブル (CREATE TMEPORARY TABLE を使用して作成するテーブル) については、現在のセッションでのみ表示されるため
、実際、読み取りトランザクションでは、一時テーブルを追加、削除、および変更することもできます。 -
READ WRITE
: 現在のトランザクションが読み取り/書き込みトランザクションであることを示します。つまり、このトランザクションに属するデータベース操作はデータの読み取りまたはデータの変更のいずれかを行うことができます。 -
WITH CONSISTENT SNAPSHOT
: 一貫した読書を始めます (一貫した読書とは何かについては心配しないでください。次の章はしつこくなります)。
たとえば、読み取り専用トランザクションを開始したい場合は、次のようにステートメントの直後にREAD ONLY
この修飾子を追加します。START TRANSACTION
START TRANSACTION READ ONLY;
TART TRANSACTION
複数の S を追跡したい場合は修饰符
、コンマを使用してそれらを区切ることができます修饰符
。たとえば、読み取り専用トランザクションと一貫した読み取りを開くには、次のように記述できます。
START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT;
または、読み取り/書き込みトランザクションを開き、一貫した読み取りを行う場合は、次のように記述できます。
START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT
ただし、ここで誰もが注意する必要があるのは、いわゆるトランザクション アクセス モードを設定するために使用されること、つまり、データベース内のデータに読み取り専用または読み取り/書き込み方式でアクセスすることですREAD ONLY
。READ WRITE
トランザクションのモードを同時に読み取り専用に設定することはできません。 も読み取り/書き込みに設定されるため、ステートメントの後にREAD ONLY
と を同時に置くことはできません。また、トランザクションのアクセス モードを明示的に指定しない場合、トランザクションのアクセス モードがモードになります。READ WRITE
START TRANSACTION
读写
3.2 トランザクションを送信する
トランザクションを開始した後、トランザクションに配置する必要があるステートメントを書き続けることができます。最後のステートメントが書き込まれた後、トランザクションを送信できます。送信されたステートメントも非常に単純です:COMMIT [WORK]
COMMIT
このステートメントはトランザクションの提出を表しており、以下はWORK
必須ではありません。たとえば、上で Zhang San が Li Si に 10 元を送金したと述べましたが、これは実際には MySQL の 2 つのステートメントに相当します。これら 2 つのステートメントを 1 つのトランザクションに入れることができます。完全なプロセスは次のとおりです。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> UPDATE account SET balance = balance + 10 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
3.3 トランザクションを手動で中止する
いくつかのステートメントを作成し、上記のステートメントの 1 つが間違っていることが判明した場合は、次のステートメントを手動で使用して、データベースをトランザクションが実行される前の状態に復元できます。ROLLBACK [WORK]
ROLLBACK
このステートメントはトランザクションの一時停止とロールバックを意味し、以下はWORK
オプションであり同様のものです。たとえば、Zhang San から Li Si への 10 元の送金に対応する MySQL ステートメントを作成したとき、最初に Zhang San から 10 元を差し引き、その後、しばらくの間 Li Si の口座に 1 元だけを追加しました。ステートメントを使用してロールバックしますROLLBACK
。完全なプロセスは次のようになります。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> UPDATE account SET balance = balance + 1 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
ここで強調する必要があるのは、ROLLBACK
このステートメントはプログラマがトランザクションを手動でロールバックするために使用されるということです。トランザクションの実行中にエラーが発生し、実行を続行できない場合、トランザクションは自動的にロールバックされます。
小提示:
ここで説明しているトランザクションのオープン、送信、および中止の構文は、ブラック ボックスを使用するときに mysql クライアント プログラムを介してサーバーと対話するときのトランザクションを制御する構文のみを対象としています。JDBC などの他のクライアント プログラムを使用する場合は、次に、対応するドキュメントを参照して、トランザクションを制御する方法を確認する必要があります。
3.4 トランザクションをサポートするストレージ エンジン
MySQL のすべてのストレージ エンジンがトランザクション関数をサポートしているわけではありません。現時点では、トランザクションをサポートするInnoDB
ストレージNDB
エンジンのみ (トランザクションに、トランザクションをサポートしていないストレージ エンジンを使用するテーブルの変更が含まれる場合、トランザクションをサポートしていないストレージ エンジンに加えられた変更は含まれています)。テーブルはロールバックされません。たとえば、tbl1
トランザクション をサポートするストレージ エンジンInnoDB
と、tbl2
トランザクション をサポートしないストレージ エンジンを使用する 2 つのテーブルがありますMyISAM
。それらのテーブル作成ステートメントは次のとおりです。
mysql> CREATE TABLE demo14 (
i int
) engine=InnoDB;
Query OK, 0 rows affected (0.05 sec)
mysql> CREATE TABLE demo15 (
i int
) ENGINE=MyISAM;
Query OK, 0 rows affected (0.01 sec)
最初にトランザクションを開始すること、挿入ステートメントを作成してからトランザクションをロールバックすることの違いを見てみましょうdemo14
。demo15
mysql> SELECT * FROM demo14;
Empty set (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO demo14 VALUES(1);
Query OK, 1 row affected (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM demo14;
Empty set (0.00 sec)
demo14
トランザクションをサポートするストレージ エンジンを使用するテーブルの場合、レコードを挿入してロールバックすると、demo14
レコードが挿入されなかったときの状態に戻ることがわかります。テーブルのパフォーマンスをもう一度見てくださいdemo15
。
mysql> SELECT * FROM demo14;
Empty set (0.01 sec)
mysql> SELECT * FROM demo15;
Empty set (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO demo15 VALUES(1);
Query OK, 1 row affected (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SELECT * FROM demo15;
+------+
| i |
+------+
| 1 |
+------+
1 row in set (0.01 sec)
ROLLBACK
このステートメントを使用してトランザクションをロールバックしましたが、挿入されたレコードはdemo15
テーブルに残っていることがわかります。
3.5 自動送信
MySQL にはシステム変数がありますautocommit
。
mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)
mysql> set persist autocommit = 'ON';
Query OK, 0 rows affected (0.00 sec)
そのデフォルト値ON
は、つまりデフォルトでは、明示的にSTART TRANSACTION
orBEGIN
ステートメントを使用してトランザクションを開始しない場合、各ステートメントは独立したトランザクションとみなされます。この機能は、トランザクションを送信します。Zhang San が Li Si に 10 元を送金するときにSTART TRANSACTION
orステートメントBEGIN
でトランザクションを明示的に開始しない場合、次の 2 つのステートメントは 2 つの独立したトランザクションで実行されるのと同じです。
UPDATE account SET balance = balance - 10 WHERE id = 1;
UPDATE account SET balance = balance + 10 WHERE id = 2;
もちろん、このアクティブな送信機能をオフにしたい場合は、次の 2 つの方法のいずれかを使用できます。
- 明示的な use
START TRANSACTION
またはBEGIN
ステートメントによってトランザクションが開始されます。このようにして、トランザクションがコミットまたはロールバックされる前に、アクティブ コミット機能が一時的に無効になります。 - 次のように、システム変数の値
autocommit
を に設定します。OFF
SET autocommit = OFF;
この場合、トランザクションをCOMMIT
コミットするステートメントを明示的に作成するか、トランザクションをROLLBACK
ロールバックするステートメントを明示的に作成するまで、作成する複数のステートメントは同じトランザクションに属します。
3.6 暗黙的なコミット
START TRANSACTION
orステートメントを使用しBEGIN
てトランザクションを開始するか、autocommit
システム変数の値OFF
を に、トランザクションは自動的に送信されませんが、いくつかのステートメントを入力すると、入力したのと同じように静かに送信されますCOMMIT
。ステートメントは同様に、いくつかの特別なステートメントによってトランザクションがコミットされるこの種の状況は と呼ばれます隐式提交
。暗黙的にトランザクションをコミットさせるステートメントには次のものが含まれます。
-
データベース オブジェクトのデータ定義言語 (データ定義言語、略称:
DDL
) を定義または変更します。いわゆるデータベース オブジェクトとは、データベース、テーブル、ビュー、ストアド プロシージャなどを指します。CREATE
、ALTER
、およびその他のステートメントを使用してDROP
これらのいわゆるデータベース オブジェクトを変更すると、次のように、前のステートメントが属するトランザクションを暗黙的にコミットします。 #トランザクション内のステートメント #トランザクション内のステートメント
BEGIN;
SELECT ...
#
UPDATE ...
トランザクション
...
内のその他ステートメント
CREATE TABLE ...
# `このステートメントは、前のステートメントが属するトランザクションを暗黙的にコミットします -
mysql
データベース内のテーブルの暗黙的な使用または変更、、、、、Sなどのステートメントを
使用すると、前のステートメントが属するトランザクションも暗黙的に送信されます。ALTER USER
CREATE USER
DROP USER
GRANT
RENAME USER
REVOKE
ET PASSWORD
-
トランザクション制御またはロックに関するステートメント トランザクションがコミットまたはロールバックされる前に、 STARTまたはステートメントを
使用して別のトランザクションを開くと、次のように、前のトランザクションが暗黙的にコミットされます。トランザクション# トランザクション内の他のステートメント# このステートメントは、前のステートメントが属するトランザクションを暗黙的にコミットしますTRANSACTION
BEGIN
BEGIN;
SELECT ...
UPDATE ...
...
BEGIN;
autocommit
または、現在のシステム変数の値をOFF
手動で に調整するON
と、前のステートメントが属するトランザクションも暗黙的にコミットされます。または、「LOCK TABLES」、「UNLOCK TABLES」、およびロックに関するその他のステートメントを使用すると、前のステートメントが属するトランザクションが暗黙的にコミットされます。
-
データをロードするためのステートメント: たとえば、
LOAD DATA
ステートメントを使用してデータをデータベースにバッチでインポートする場合、前のステートメントが属するトランザクションも暗黙的に送信されます。 -
MySQL レプリケーションに関する一部のステートメントは、、 、、およびその他のステートメント
を使用するときに、前のステートメントが属するトランザクションを暗黙的にコミットします。START SLAVE
STOP SLAVE
RESET SLAVE
CHANGE MASTER TO
-
、、、、、 、、およびその他のステートメント
を使用する他の一部のステートメントも、前のステートメントが属するトランザクションを暗黙的にコミットします。ANALYZE TABLE
CACHE INDEX
CHECK TABLE
FLUSH
LOAD INDEX INTO CACHE
OPTIMIZE TABLE
REPAIR TABLE
RESET
小提示:
上記のステートメントの一部は、すべてを理解し、何に使用されるかを知っていれば素晴らしいことですが、知らなくても落胆しないでください。これらは、内容の完全性を保つためにここに書かれています。すべての状況と、それぞれのステートメントが何に使用されるかをリストアップして、それに遭遇したときに話しましょう。
3.7 セーブポイント
トランザクションを開始して多くのステートメントを入力し、最後のステートメントに何か問題があることに突然気づいた場合は、そのステートメントを使用してデータベースの状態をトランザクションが実行される前の状態に復元してから、すべてのステートメントを開始する必要がありますROLLBACK
。繰り返しますが、以前は常に、一晩にして解放への回帰のような感覚があります。したがって、データベースは保存点
(英語: savepoint
) という概念を提案しています。これは、トランザクションに対応するデータベース ステートメント内のいくつかのポイントをマークすることです。ステートメントを呼び出すときに、ROLLBACK
元の原点に戻るのではなく、どのポイントにロールするかを指定できます。 。セーブポイントを定義するための構文は次のとおりです。SAVEPOINT 保存点名称
セーブポイントにロールバックしたい場合は、次のステートメントを使用できます (次のステートメント内の単語の合計はオプションWORK
ですSAVEPOINT
)。ROLLBACK [WORK] TO [SAVEPOINT] 保存点名称
ただし、ROLLBACK
ステートメントがセーブポイントの名前に従っていない場合、トランザクション実行前の状態に直接ロールバックされます。
セーブポイントを削除したい場合は、次のステートメントを使用できます。RELEASE SAVEPOINT 保存点名称
以下は、Zhang San が用途を示すために Li Si に 10 元を送金する例です保存点
。Zhang San の口座からお金を差し引くステートメントを実行した後、10元
a と入力します保存点
。
mysql> SELECT * FROM account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 12 |
| 2 | 李四 | 2 |
+----+--------+---------+
2 rows in set (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SAVEPOINT s1; # 一个保存点
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 2 |
| 2 | 李四 | 2 |
+----+--------+---------+
2 rows in set (0.00 sec)
mysql> UPDATE account SET balance = balance + 1 WHERE id = 2; # 更新错了
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> ROLLBACK TO s1; # 回滚到保存点s1处
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 2 |
| 2 | 李四 | 2 |
+----+--------+---------+
2 rows in set (0.01 sec)
今日の勉強はこれで終わりです、あなたが壊れない自分になれることを願っています
~~~
先を見据えて点と点を結ぶことはできません。過去を振り返って接続することしかできません。したがって、点と点が何らかの形であなたの将来につながると信じなければなりません。あなたは何かを信頼しなければなりません - 自分の直感、運命、人生、カルマ、何でも。このアプローチは私を決して失望させず、私の人生に大きな変化をもたらしました
私のコンテンツがあなたのお役に立てましたら、どうぞ点赞
、、、創作は簡単ではありません、皆さんのサポートが私が頑張れる原動力です评论
收藏