ホームページ  >  記事  >  データベース  >  mysqlの酸とは何ですか

mysqlの酸とは何ですか

醉折花枝作酒筹
醉折花枝作酒筹転載
2021-05-08 10:42:105840ブラウズ

この記事では、mysql の酸について紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。

mysqlの酸とは何ですか

1. トランザクションの基本要素 (ACID)

1. 原子性: トランザクション開始後のすべての操作、どちらかを実行全部やるか、まったくやらないか、途中で行き詰まってしまうのは不可能です。トランザクションの実行中にエラーが発生した場合、トランザクションが開始される前の状態にロールバックされ、すべての操作は発生しなかったかのように行われます。つまり、物事は、化学で習う物質の基本単位である原子のように、分割できない全体であるということです。

2. 一貫性: トランザクションの開始および終了の前後で、データベースの整合性制約は破壊されません。たとえば、A が B にお金を送金した場合、A がそのお金を差し引くが、B が受け取らないということは不可能です。実際、一貫性は原子性の現れでもあります。

3. 分離: 同時に、同じデータを要求できるのは 1 つのトランザクションだけであり、異なるトランザクション間の干渉はありません。たとえば、A は銀行カードからお金を引き出していますが、B は A の引き出しプロセスが完了するまでこのカードにお金を送金することはできません。シリアル化

4. 耐久性: トランザクションが完了すると、トランザクションによるデータベースへのすべての更新はデータベースに保存され、ロールバックすることはできません。

2. トランザクションの同時実行の問題

1. ダーティ リード: トランザクション A がトランザクション B によって更新されたデータを読み取り、B が操作をロールバックしてから、A が受信したデータはダーティ データであり、テーブル内の最終的な実際のデータと一致しません。

2. 反復不可能な読み取り: トランザクション A は同じデータを複数回読み取り、トランザクション B はトランザクション A で同じデータを複数回読み取ります。データが更新されて送信されたため、トランザクション A が同じデータを複数回読み取ると、一貫性のない結果が発生しました。読み取り結果は前回の結果と一致しません

3. ファントム読み取り: システム管理者 A はデータベース内のすべての生徒の成績を特定のスコアから ABCDE 成績に変更しましたが、システム管理者 B はこの時点でレコードを挿入しました。システム管理者Aが特定のスコアのレコードを修正した後、あたかも幻覚が起こったかのように、修正されていないレコードが1つ残っていることに気づきました。これをファントムリーディングといいます。変更された後変更され、予想とは異なる結果になりました

要約: 非再現読み取りとファントム読み取りは混同されやすいです。非再現読み取りは変更に焦点を当て、ファントム読み取りは追加または削除に焦点を当てます。 。反復不能読み取りの問題を解決するには、条件を満たす行をロックするだけでよく、ファントム読み取りの問題を解決するには、テーブルをロックする必要があります

3. MySQL トランザクション分離レベル

#トランザクション分離レベル#Non-repeatable readYes##No ##Yes#Yes##Noいいえはい##NoNoNo

mysql のデフォルトのトランザクション分離レベルは反復読み取り可能です

##4. 例を使用して各分離レベルを説明します

1 . Read uncommitted:

(1) クライアント A を開き、現在のトランザクション モードを read uncommitted (非コミット読み取り) に設定し、テーブル アカウントの初期値をクエリします:

# (2) クライアント A のトランザクションがコミットされる前に、別のクライアント B を開いてテーブル アカウントを更新します。

(3) この時点では、クライアントB のトランザクションはまだ送信されていないため、クライアント A は B の更新されたデータをクエリできます:


(4) クライアント B が何らかの理由でトランザクションがロールバックされると、その場合、クライアント A によってクエリされたデータは、実際にはダーティ データです:

(5) クライアント A で、更新ステートメントを実行します update account setbalance = Balance - id =1の50です。リレイの残高は350ではなく、実際は400です。おかしくありませんか。データが矛盾しています。そう思っているなら、あなたは甘すぎます。アプリケーションでは、400-50=350を使用します。 , そして、他のセッションがロールバックされたことはわかりません。この問題を解決するには、読み取りコミット分離レベル

2. コミットされた読み取り

(1) クライアント A を開き、現在のトランザクション モードをコミット済み読み取り (アンコミット読み取り) に設定し、テーブル アカウントの初期値をクエリします。

(2) クライアント A のトランザクションがコミットされる前に、別のクライアント B を開いてテーブル アカウントを更新します:

クライアント B のトランザクションはまだ送信されていません。クライアント A B の更新データをクエリできません。これにより、ダーティ リード問題が解決されます。

(4) クライアント B のトランザクション Submit

(5) クライアント A が前のステップと同じクエリを実行すると、結果が前のステップと矛盾します。つまり、反復不可能な読み取りの問題が発生します。

3 .Repeatable read

(1) クライアント A を開き、現在のトランザクション モードをrepeatable readに設定し、テーブル アカウントをクエリします

(2) Beforeクライアント A のトランザクションが送信され、別のクライアント B を開き、テーブル アカウントを更新して送信します。

# # エンド A は、ステップ (1) のクエリを実行します。

# Aticbility:非反復性の読み取り問題が発生します。その後、更新バランス=バランス-50ここでid = 1で、残高は400-50 = 350になりません。 lileiのバランス値は(2)の350を使って計算されているので、データの整合性は崩れていない300になっています。これはちょっと不思議です。mysqlの機能なのかもしれません。dmlをする際に、データがテーブルの実データに従って繰り返し読み取ることができます

mysql> select * from account;
+------+--------+---------+
| id   | name   | balance |
+------+--------+---------+
|    1 | lilei  |     400 |
|    2 | hanmei |   16000 |
|    3 | lucy   |    2400 |
+------+--------+---------+
3 rows in set (0.00 sec)

mysql> update account set balance = balance - 50 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from account;
+------+--------+---------+
| id   | name   | balance |
+------+--------+---------+
|    1 | lilei  |     300 |
|    2 | hanmei |   16000 |
|    3 | lucy   |    2400 |
+------+--------+---------+
3 rows in set (0.00 sec)

(5) クライアントAの場合 トランザクションをサブミットし、テーブルアカウントの初期値をクエリします

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
+------+--------+---------+
| id | name | balance |
+------+--------+---------+
| 1 | lilei | 300 |
| 2 | hanmei | 16000 |
| 3 | lucy | 2400 |
+------+--------+---------+
3 rows in set (0.00 sec)

(= 7 クライアントAの場合残高の合計を計算します。値は 300 16000 2400 = 18700 です。クライアント B の値は含まれません。クライアント A が送信した後、残高の合計が計算され、19300 になります。これは、クライアントの値がB が計算されます。B の 600 が含まれます

,站在客户的角度,客户是看不到客户端B的,它会觉得是天下掉馅饼了,多了600块,这就是幻读,站在开发者的角度,数据的 一致性并没有破坏。但是在应用程序中,我们得代码可能会把18700提交给用户了,如果你一定要避免这情况小概率状况的发生,那么就要采取下面要介绍的事务隔离级别“串行化” 

mysql> select sum(balance) from account;
+--------------+ 
| sum(balance) | 
+--------------+ 
| 18700 |
+--------------+
1 row in set (0.00 sec)
mysql> commit;
 Query OK, 0 rows affected (0.00 sec)
mysql> select sum(balance) from account;
 +--------------+ 
 | sum(balance) | 
 +--------------+
 | 19300 |
 +--------------+ 
 1 row in set (0.00 sec)

  4.串行化

    (1)打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值:

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
+------+--------+---------+
| id   | name   | balance |
+------+--------+---------+
|    1 | lilei  |   10000 |
|    2 | hanmei |   10000 |
|    3 | lucy   |   10000 |
|    4 | lily   |   10000 |
+------+--------+---------+
4 rows in set (0.00 sec)

    (2)打开一个客户端B,并设置当前事务模式为serializable,插入一条记录报错,表被锁了插入失败,mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values(5,'tom',0);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

补充:

  1、SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异

  2、mysql中默认事务隔离级别是可重复读时并不会锁住读取到的行

  3、事务隔离级别为读提交时,写数据只会锁住相应的行

  4、事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁间隙锁、行锁、下一键锁的问题,从而锁住一些行;如果没有索引,更新数据时会锁住整张表。

  5、事务隔离级别为串行化时,读写数据都会锁住整张表

   6、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

相关推荐:《mysql教程

##ダーティリード##ファントムリード コミットされていない読み取り (コミットされていない読み取り)
Yes Yes read-committed
#Repeatable-read
#シリアル化可能

以上がmysqlの酸とは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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