MySQL データベース --- トランザクション
序文
MySQL トランザクションは主に、大量の操作と高度な複雑性を伴うデータを処理するために使用されます。たとえば、人事管理システムでは、個人を削除する場合、その個人の基本情報を削除する必要があり、その個人に関連するメールボックスや記事などの情報も削除する必要があります。このように、これらのデータベース操作ステートメントがトランザクションを構成します。
1. 物事の概念
-
トランザクションとは、一連のデータベース操作コマンドを含む一連の操作メカニズムであり、すべてのコマンド全体とともに操作要求をシステムに送信または取り消します。つまり、この一連のデータベース コマンドが実行されるか実行されないかのどちらかです。実行されました。
-
トランザクションは、分割できない論理的な作業単位であり、データベース システム上で同時操作を実行する場合の最小の制御単位です。
-
トランザクションは、銀行、保険会社、証券取引システムなど、複数のユーザーがデータベース システムを同時に操作するシナリオに適しています。
-
トランザクションは、トランザクションの整合性を通じてデータの一貫性を保証します。
端的に言えば、いわゆるトランザクションは一連の操作であり、これらの操作は実行されるか実行されないかのどちらかであり、分割できない作業単位です。
次に、トランザクションの ACID 特性
ACID は、信頼性の高いデータベース管理システム (DBMS) においてトランザクションが持つべき 4 つの特性 (原子性、一貫性、分離性、耐久性) を指します。これらは、信頼性の高いデータベースが持つべきいくつかの特性です。
- 原子性:
-
これは、トランザクションが分割できない作業単位であり、トランザクション内の操作がすべて行われるか、まったく行われないかのどちらかであることを意味します。
-
トランザクションは完全な操作であり、トランザクションの要素は分離できません。
-
トランザクション内のすべての要素は、全体としてコミットまたはロールバックする必要があります。
-
トランザクション内のいずれかの要素が失敗すると、トランザクション全体が失敗します。
-
事例:
AがBに100元を送金する際、控除明細書を作成して提出するだけで、突然停電が発生した場合、A口座はすでに引き落とされているが、B口座は追加の支払いを受け取っていないため、紛争が発生します。この場合、トランザクションが実行されるか実行されないかを保証するには、トランザクションのアトミック性が必要です。
- 一貫性:
-
これは、トランザクションの開始前とトランザクションの終了後にデータベースの整合性制約に違反していないことを意味します。
-
トランザクションが完了すると、データは一貫した状態になる必要があります。
-
トランザクションが開始される前、データベースに保存されているデータは一貫した状態にあります。
-
トランザクションの進行中、データは不整合な状態になる可能性があります。
-
トランザクションが正常に完了すると、データは再び既知の一貫した状態に戻る必要があります。
-
ケース:
銀行振込取引の場合、取引が成功するか失敗するかに関係なく、取引完了後の表の A と B の入金額の合計が取引実行前と一致していることを確認する必要があります。
- 隔離:
-
これは、同時環境では、異なるトランザクションが同じデータを同時に操作するときに、各トランザクションが独自の完全なデータ領域を持つことを意味します。
-
データを変更するすべての同時トランザクションは互いに分離されており、これは、トランザクションが独立している必要があり、他のトランザクションに依存したり影響を与えたりしてはいけないことを示しています。
データを変更するトランザクションは、同じデータを使用する別のトランザクションが開始される前、または同じデータを使用する別のトランザクションが終了した後にデータにアクセスできます。
トランザクションの実行は、他のトランザクションによって干渉されることはできません
- 永続性:
-
トランザクションが完了すると、トランザクションによってデータベースに加えられた変更はデータベースに保持され、ロールバックされません。
-
これは、システムに障害が発生したかどうかに関係なく、トランザクション処理の結果は永続的であることを意味します。
トランザクションがコミットされると、トランザクションの効果はデータベースに永続的に保持されます。
- トランザクション間の対話にはいくつかの種類があります。
-
ダーティ リード (コミットされていないデータの読み取り):
ダーティ リードとは、他のトランザクションのコミットされていないデータを読み取ることを指します。アンコミットとは、これらのデータがロールバックされる可能性があること、つまり、最終的にデータベースに格納されない可能性があることを意味します。データが存在します。読み取られ、最終的に存在する必要があるデータはダーティ リードです- たとえば、ケース 1 では
、トランザクション B が実行中にデータ X を変更しました。コミットする前に、トランザクション A は X を読み取りましたが、トランザクション B がロールバックしたため、トランザクション A はダーティ リードを形成しました。つまり、現在のトランザクションによって読み取られたデータは、他のトランザクションが変更しようとしているが、正常に変更されていないデータです。
- たとえば、ケース 1 では
-
非反復読み取り (前後に複数の読み取りがあり、データ内容に一貫性がない):
トランザクション内の 2 つの同一のクエリが異なるデータを返します。これは、クエリ時にシステム内の他のトランザクションによって変更されたコミットが原因で発生します。- ケース:
トランザクション A は最初のクエリでレコード row1 の行を取得し、トランザクション B が変更を送信した後、トランザクション A は 2 番目のクエリで row1 を取得しますが、列の内容は変更されています。
- ケース:
select * from member;
1 zhangsan 20分
select * from Member;
1 zhangsan 30分
-
ファントム読み取り (前後に複数の読み取りがあり、データの合計量が一致しない):
トランザクションはテーブル内のデータを変更します。この変更にはテーブル内のすべてのデータ行が含まれます。同時に、別のトランザクションもこのテーブルのデータを変更します。この変更は、テーブルに新しいデータ行を挿入することです。すると、前のトランザクションを操作したユーザーは、あたかも錯覚が起こったかのように、テーブル内にまだ変更されていないデータ行が存在することに気づきます。- case 列では
、トランザクション A が一部の行の内容を変更したが、まだコミットされていないことを想定しています。このとき、トランザクション B は、トランザクション A が変更する前のレコードと同じレコード行を挿入し、トランザクション A がコミットする前にコミットされます。トランザクション A でクエリを実行すると、今の変更は一部のデータに影響を与えていないことがわかりますが、実際にはトランザクション B によって挿入されただけなので、ユーザーは魔法のような幻覚を感じます。これはファントム読み取り選択と呼ばれます
*メンバーから;
6 件のレコードが見つかりました
- case 列では
alter table member change
select * from member;
查询到了10条记录 (更新了6条数据,还有4条数据,我没有更新到)
- 更新の喪失:
2 つのトランザクションが同じレコードを同時に読み取ります。A が最初にレコードを変更し、B もレコードを変更します (B は A が変更したことを知りません)。B がデータを送信した後、B の変更結果が上書きされます。 Aの修正結果です。- ケース
A 30 -> 40 トランザクション
B が最初に完了する 30 -> 50
B のトランザクション結果は A のトランザクション結果を上書きし、最終的な値は 50 になります
- ケース
3. Mysqlとトランザクション分離レベル(4種類)
- コミットされていない読み取り (コミットされていない読み取り):
- コミットされていないデータの読み取り: ダーティ リードを解決しません
- ダーティ リードが許可されているため、他のトランザクションがデータを変更している限り、コミットされていない場合でも、このトランザクションは変更されたデータ値を参照できます。つまり、他のセッションのコミットされていないトランザクションによって変更されたデータを読み取ることができます。
- コミットされた読み取り (読み取りを送信):
- コミットされたデータの読み取り: ダーティ読み取りは解決可能
- 送信されたデータのみを読み取ることができます。Oracle などのほとんどのデータベースは、デフォルトでこのレベル (反復不可読み取り) に設定されています。
- 反復可能な読み取り (再現性):
- 再読み取り: ダーティ リードと反復不可能な読み取りを解決できます - mysql のデフォルト
- 繰り返し読める読書。他のトランザクションがデータを変更およびコミットしたかどうかに関係なく、このトランザクションで表示されるデータ値は常に他のトランザクションの影響を受けません。
- シリアル化可能: シリアル化可能:
- ダーティ リード、非反復読み取り、ファントム読み取り (ロック テーブルと同等)、完全にシリアル化された読み取りを解決できます
。各読み取りはテーブル レベルの共有ロックを取得する必要があり、読み取りと書き込みは相互にブロックされます。
MySQL のデフォルトのトランザクション レベルは反復読み取りですが、Oracle と SQL Server は読み取りコミットです。
- トランザクション分離レベルの範囲(2種類)
-
グローバル レベル: すべてのセッションに有効 (グローバル設定はデータベースのセッション レベルにロードされ、グローバル設定は再起動後に有効になります)
-
セッション レベル: 現在のセッションでのみ有効 (即時有効)
-
グローバルトランザクション分離レベルを問い合わせる
set global transaction isolation level read committed;
#例:
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
mysql> show global variables like '%isolation%';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED | //已经改为提交读
+---------------+----------------+
1 row in set (0.00 sec)
- セッショントランザクション分離レベルを設定する
set session transaction isolation level read committed;
#例:
mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
mysql> show session variables like '%isolation%';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED | //查看已经更改为提交读
+---------------+----------------+
1 row in set (0.00 sec)
4. トランザクション制御文
BEGIN 或 START TRANSACTION:显式地开启一个事务。
COMMIT 或 COMMIT WORK:提交事务,并使已对数据库进行的所有修改变为永久性的。
ROLLBACK 或 ROLLBACK WORK:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
SAVEPOINT S1:使用 SAVEPOINT 允许在事务中创建一个回滚点,一个事务中可以有多个 SAVEPOINT;“S1”代表回滚点名称。
ROLLBACK TO [SAVEPOINT] S1:把事务回滚到标记点。
- レンプレート:
mysql> create database test; //创建test库
Query OK, 1 row affected (0.00 sec)
mysql> use test; //切换到test
Database changed
mysql> create table info( //创建info表
-> id int(10) primary key not null,
-> name varchar(40),
-> money double
-> );
Query OK, 0 rows affected (0.15 sec)
mysql> insert into info values(1,'A',1000); //添加数据
Query OK, 1 row affected (0.00 sec)
mysql> insert into info values(2,'B',1000); //添加数据
Query OK, 1 row affected (0.00 sec)
mysql> select * from info; //查询数据
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 1000 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec
- テストコミットトランザクション
mysql> begin; //开启事务
Query OK, 0 rows affected (0.00 sec)
mysql> update info set money= money - 100 where name='A'; //事务
select * from info;
mysql> commit; //提交事务
###退出重进
quit
mysql -u root -p
use SCHOOL;
mysql> select * from info; //数据已经被更改
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 900 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec)
- ロールバックトランザクションのテスト
mysql> select * from info;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 900 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec)begin;
mysql> begin; //开启事务
Query OK, 0 rows affected (0.00 sec)
mysql> update info set money= money + 100 where name='A'; //修改数据
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from info; //查看
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 1000 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec)
mysql> rollback; //回滚
Query OK, 0 rows affected (0.00 sec)
####退出重进
mysql> quit
mysql -u root -p
mysql> use SCHOOL;
mysql> select * from info; //再次查看,数据已经回滚
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 900 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec)
- マルチポイントロールバックをテストする
mysql> begin; //开启事务
mysql> update info set money= money + 100 where name='A'; //修改更新数据
mysql> select * from info; //查看数据
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 1000 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec)
mysql> savepoint s1; //创建回滚点s1
Query OK, 0 rows affected (0.00 sec)
mysql> update info set money= money + 100 where name='B'; //修改更新数据
mysql> select * from info;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 1000 |
| 2 | B | 1100 |
+----+------+-------+
2 rows in set (0.00 sec)
mysql> savepoint s2; //创建回滚点s2
Query OK, 0 rows affected (0.00 sec)
mysql> insert into info values(3,'C',1000); //插入新数据
Query OK, 1 row affected (0.00 sec)
mysql> select * from info;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 1000 |
| 2 | B | 1100 |
| 3 | C | 1000 |
+----+------+-------+
3 rows in set (0.00 sec)
mysql> rollback to s1; //回滚到s1
Query OK, 0 rows affected (0.00 sec)
mysql> select * from info; //再次查看发现数据已经回滚
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | A | 1000 |
| 2 | B | 1000 |
+----+------+-------+
2 rows in set (0.00 sec)
- セット設定を使用してトランザクションを制御する
SET AUTOCOMMIT=0; #禁止自动提交
SET AUTOCOMMIT=1; #开启自动提交,Mysql默认为1
SHOW VARIABLES LIKE 'AUTOCOMMIT'; #查看Mysql中的AUTOCOMMIT值
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)
如果没有开启自动提交,当前会话连接的mysql的所有操作都会当成一个事务直到你输入rollback|commit;当前事务才算结束。当前事务结束前新的mysql连接时无法读取到任何当前会话的操作结果。
如果开起了自动提交,mysql会把每个sql语句当成一个事务,然后自动的commit。
当然无论开启与否,begin; commit|rollback; 都是独立的事务。
use SCHOOL;
select * from info;
SET AUTOCOMMIT=0; //禁止自动提交
SHOW VARIABLES LIKE 'AUTOCOMMIT'; //查看Mysql中的AUTOCOMMIT值
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | NO |
+---------------+-------+
update info set money= money + 100 where name='B';
select * from info;
quit
mysql -u root -p
use SCHOOL;
select * from info;
要約する
-
物事の ACID 特性は、原子性、一貫性、分離性、永続性です。
-
トランザクション間の対話は、ダーティ リード、非反復読み取り、ファントム リード、ロスト アップデートに分類されます。
-
トランザクション分離レベルは、非コミット読み取り (アンコミット読み取り)、コミット読み取り (コミット読み取り)、反復可能読み取り (反復可能)、シリアライズ可能: シリアル化に分類されます。
-
mysql のデフォルトのトランザクション処理レベルは反復読み取りです。
-
トランザクション分離レベルの範囲は
、グローバル レベル: すべてのセッションに有効、
セッション レベル: 現在のセッションにのみ有効に分かれています。