ホームページ  >  記事  >  データベース  >  MySQL のトランザクション、4 つの主要な機能、分離レベルについての深い理解

MySQL のトランザクション、4 つの主要な機能、分離レベルについての深い理解

青灯夜游
青灯夜游転載
2021-10-12 10:51:201762ブラウズ

この記事は、MySQL の高度な研究です。MySQL のトランザクション、4 つの主要な機能 (ACID)、およびトランザクションの分離レベルについて詳しく説明します。お役に立てば幸いです。

MySQL のトランザクション、4 つの主要な機能、分離レベルについての深い理解

[関連する推奨事項: mysql ビデオ チュートリアル ]

この記事の操作とテストに使用した環境のバージョンは ## です#5.7.21

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.21    |
+-----------+
1 row in set (0.00 sec)

覚えておいてください:

一般的な MySQL ストレージ エンジンの中でトランザクションをサポートしているのは InnoDB だけです。したがって、次の操作も InnoDB で実行されます。

1. トランザクションとは何ですか

トランザクションは現実から抽象化された論理操作であり、すべての操作が実行されるか、または実行されます。いずれも実行ではないため、部分的な実行はできません。
より典型的なケースは銀行振込です。小さな A が小さな B に 100 元を送金します。

通常の状況: 小さな A の口座から 100 元が差し引かれ、小さな B の口座から 100 元が増額されます。

異常事態: A さんの口座から 100 元が差し引かれ、B さんの口座の金額は変わりません。

異常な状況下で、小人 A の口座から 100 元が引き落とされた後、銀行システムに問題が発生し、小人 B の口座に 100 元を追加する操作は実行されませんでした。つまり、両側の金額が一致せず、小さな A もその気がなく、小さな B もその意志がなく、銀行も同様です。不倫の目的は、異常事態を回避し、全員を満足させることです。

2. トランザクションの 4 つの主要な特徴 (ACID)

1. アトミック性

トランザクションの操作は分割できず、すべての操作を行うかまったく操作しないかのどちらかです。転送と同様に、中間状態はありません。そして、この原子性は、アクションが 1 つだけあるという意味ではなく、多くの操作がある可能性がありますが、結果から切り離すことはできません。つまり、原子性は結果の状態です。

2. 一貫性

銀行口座システムと同様に、トランザクションの実行前と実行後、データは一貫性を保ちます。両者の合計口座金額は同じである必要があります。

3. 分離

複数のトランザクションが同時にデータを操作する場合、複数のトランザクションは直接分離され、相互に影響を与えることはありません。

4. 耐久性

送信後のデータに対するトランザクションの影響は永続的で、ディスクに書き込まれたときに失われることはありません。

#3. 明示的トランザクションと暗黙的トランザクションmysql トランザクションは、

明示的トランザクション

暗黙的トランザクションに分けられます。 、デフォルトのトランザクションは暗黙的なトランザクションであり、変数 autocommit によって操作中に自動的にオープン、コミット、ロールバックされます。 制御のための主なコマンドは次のとおりです

set autocommit=0; -- 关闭自动提交事务(显式)
set autocommit=1; -- 开启自动提交事务(隐式)
  -- 当autocommit=0的时候手动控制事务
rollback; -- 回滚事务
commit;  -- 提交事务
-- 当autocommit=1 自动提交事务,但是可以控制手动提交
start transaction; -- 开启事务(或者用begin开启事务)
commit; -- 提交事务
rollback; -- 回滚事务
SAVEPOINT 保存点名称;  -- 保存点(相当于存档,可以不用回滚全部操作)
rollback to  保存点;  -- 回滚到某个保存点 (这个后面就不测试,知道有这个操作就行)

最初にテーブル ajisun

mysql> create table ajisun(id int(5), name varchar(20) character set utf8  COLLATE utf8_bin ) engine=innodb character set= utf8mb4 COLLATE = utf8mb4_bin;
Query OK, 0 rows affected (0.03 sec)

1 を作成します。暗黙のトランザクション

-- 看下当前autocommit的状态是,默认是on状态
mysql> show variables like 'autocommit'; 
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

--  插入一条数据
mysql> insert into ajisun values(1,'阿纪');
Query OK, 1 row affected (0.00 sec)
mysql> rollback;

-- 执行rollback 也是没有效果的,还是能够查询到插入的数据(不需要我们手动控制commit)
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
+------+--------+
1 row in set (0.00 sec)

2. 明示的トランザクション モード 1

明示的トランザクションにより、トランザクションのオープン、送信、ロールバック、その他の操作を制御できます

-- 开启显式事务-回滚
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
+------+--------+
1 row in set (0.00 sec)

mysql> insert into ajisun values(2,'纪先生');
Query OK, 1 row affected (0.00 sec)
-- 插入后可以看见2条数据
mysql> select * from ajisun;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | 阿纪      |
|    2 | 纪先生    |
+------+-----------+
2 rows in set (0.00 sec)
-- 回滚之后上面插入的数据就没了
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
+------+--------+
1 row in set (0.00 sec)
-- 插入一条数据
mysql> insert into ajisun values(2,'ajisun');
Query OK, 1 row affected (0.01 sec)
-- 提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
-- 回滚
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
-- 先提交commit,在rollback 数据依然存在,说明commit生效,事务已提交,回滚就不生效了。
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
|    2 | ajisun |
+------+--------+
2 rows in set (0.00 sec)

3. 明示的トランザクション方法 2

開始トランザクションを使用します

最初にデフォルトのトランザクションに変更します

set autocommit=1;

<pre class="brush:js;toolbar:false;">-- 开启事务 mysql&gt; start transaction; Query OK, 0 rows affected (0.00 sec) mysql&gt; delete from ajisun where id=1; Query OK, 1 row affected (0.00 sec) -- 提交事务 mysql&gt; commit; Query OK, 0 rows affected (0.01 sec) mysql&gt; select * from ajisun; +------+--------+ | id | name | +------+--------+ | 2 | ajisun | +------+--------+ 1 row in set (0.00 sec)</pre><pre class="brush:js;toolbar:false;">-- 开启事务 mysql&gt; start transaction; Query OK, 0 rows affected (0.00 sec) mysql&gt; delete from ajisun where id =2; Query OK, 1 row affected (0.01 sec) -- 回滚事务 mysql&gt; rollback; Query OK, 0 rows affected (0.01 sec) -- 删除操作失效了 mysql&gt; select * from ajisun; +------+--------+ | id | name | +------+--------+ | 2 | ajisun | +------+--------+ 1 row in set (0.00 sec)</pre>

4. 同時トランザクションの問題テーブル上で同時に動作するトランザクションが 1 つだけであれば問題ありませんが、これは不可能です。実際には可能な限り使用し、複数のトランザクションを同時に実行します。複数のトランザクションは、

Dirty read

Dirty write`Non-repeatable readphantom read などの多くの問題を引き起こします。

1. ダーティ リード

#トランザクションは、コミットされていない別のトランザクションから変更されたデータを読み取ります。これはダーティ リードです。

たとえば、2 つのトランザクション a と b: 同時にレコードを操作します

トランザクション a がレコードを変更した後、そのレコードはデータベースに正式に送信されていません。時刻にトランザクション b がそれを読み取り、次に read を使用します。取得されたデータは後続の操作に使用されます。

トランザクション a がロールバックされ、変更されたデータが存在しない場合、トランザクション b は存在しないデータを使用しています。これはダーティデータです。

#2. ダーティ ライト (データ損失)

あるトランザクションが、別のコミットされていないトランザクションによって変更されたデータを変更しました

例、2 つのトランザクション a と b: レコードを同時に操作します。

A トランザクションは変更後に送信されず、その後、b トランザクションも同じデータを変更し、その後、b トランザクションがデータをコミットします。

トランザクション a が自身の変更をロールバックし、トランザクション b の変更もロールバックする場合、問題は次のようになります: トランザクション b は変更および送信されましたが、データベースは変更されていません。この状況はダーティ ライティングです。

3. 反復不可能な読み取り

トランザクションは、コミットされた別のトランザクションによって変更されたデータのみを読み取ることができ、他のトランザクションはデータを読み取ることはできません。変更が行われて送信されると、トランザクションをクエリして最新の値を取得できます。

也就是在同一个事务中多次读取同一条记录,得到的内容都不一样(在每次读取之前都有其他事务完成修改并提交),这就是不可重复读

4. 幻读

在一个事务内 相同条件查询数据,先后查询到的记录数不一样

也就是一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读

不可重复读和幻读的区别:不可重复读重点在于同一条记录前后数据值不一样(内容的变化),而幻读重点在于相同查询条件前后所获取的记录数不一样(条数的变化)

五. 事务的隔离级别

上面说的事务的并发问题,在不同的场景下要求不一样,能接受的问题也不一样。他们之间的严重性排序如下:

脏写 > 脏读 > 不可重复读 > 幻读

MySQL中提供了4种隔离级别来处理这几个问题,如下

隔离级别 脏读 不可重复读 幻影读
READ- UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

SQL 标准定义了四个隔离级别:

  • READ-UNCOMMITTED(读未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读不可重复读幻读。但是并发度最高
  • READ-COMMITTED(读已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,该级别可以防止脏读不可重复读以及幻读。并发度也是最低的
MySQL默认采用的 REPEATABLE_READ 隔离级别 
Oracle默认采用的 READ_COMMITTED 隔离级别

1. 如何设置隔离级别

可以通过变量参数transaction_isolation 查看隔离级别

mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

mysql> show variables like &#39;%transaction_isolation%&#39;;
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)

修改的命令:SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL $[level];

level的值就是4中隔离级别READ-UNCOMMITTED READ-COMMITTED REPEATABLE-READ SERIALIZABLE

设置全局隔离级别

只对执行完该语句之后产生的会话起作用。

当前已经存在的会话无效。

set global transaction_isolation=&#39;read-uncommitted&#39;;
set global transaction_isolation=&#39;read-committed&#39;;
set global transaction_isolation=&#39;repeatable-read&#39;;
set global transaction_isolation=&#39;serializable&#39;;

例如:

会话A

mysql> set global transaction_isolation=&#39;serializable&#39;;
Query OK, 0 rows affected (0.01 sec)
mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)
-- 当前会话(设置之前就已经存在的会,级别是默认的)
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

会话B(set之后新建的会话)

mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE            |
+-------------------------+
1 row in set (0.00 sec)

设置会话的隔离级别

对当前会话的所有后续的事务有效

该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务。

如果在事务之间执行,则对后续的事务有效。

set session transaction_isolation=&#39;read-uncommitted&#39;;
set session transaction_isolation=&#39;read-committed&#39;;
set session transaction_isolation=&#39;repeatable-read&#39;;
set session transaction_isolation=&#39;serializable&#39;;

比如:

会话A

mysql> set session transaction_isolation=&#39;read-uncommitted&#39;;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row in set (0.00 sec)

新建会话B(依然是默认的级别:可重复读)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

2. 怎么选择隔离级别

一般情况下默认的可重复读就好了,一般很少改这个,除非业务场景特殊

记住一点:隔离级别越高,并发问题就越少,但并发性也就越低,所以还是要根据业务选择来。

六. 总结

  • 事务的四大特性:原子性,一致性,隔离性,持久性

  • 事务的常见命令:

    set autocommit=0/1; -- 关闭/开启自动提交事务
    start transaction; -- 开启事务(或者用begin)
    rollback; -- 回滚事务
    commit; -- 提交事务
  • 并发事务的问题:脏写 > 脏读 > 不可重复读 > 幻读

  • 需要熟悉事务的4种隔离级别以及MySQL默认级别

  • 怎么设置隔离级别(global,session)

更多编程相关知识,请访问:编程入门!!

以上がMySQL のトランザクション、4 つの主要な機能、分離レベルについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。