MySQLのトランザクション分離レベルと並行性の業務上の問題の異なる分離レベル

まず、トランザクションの4つの特性(ACID)

1、アトミック(不可分)

     取引はすべて、またはそれらのどれもいずれかで行う、すべての操作を開始した後。トランザクションは不可分の全体です。トランザクション開始前に実装プロセスでのトランザクションのエラーは、トランザクションの整合性を確保するために、状態にロールバックされます。

2.一貫性(整合性)

    開始と終了後の取引は、データの整合性で、データベースの整合性制約の正確さを確保します。例えば振替、Bに転送、私たちはお金がAを控除し、Bがお金を受け取ることができるようになることを確認する必要があります。

図3に示すように、分離(単離)

     トランザクション間の完全分離、互いに独立して二つのトランザクション。Aの終わりがこのカードの操作に他のトランザクションに許可されていません前ので、銀行カードへの転送として、アカウントに同時に欠陥の量を操作した結果をすぎを避けるために。

図4に示すように、永続的な(耐久性)

     トランザクションのデータへの変更は永続的です。人気の説明トランザクションが完了した後、操作はディスクからのデータに行われるべきである(永続的)。トランザクションが不可逆的で完了すると、一度完了したトランザクションのためのデータベースのパフォーマンスはロールバックされません。

第二に、問題が同時トランザクションによって引き起こされます

1、ダーティー読み取り

      トランザクションが別のトランザクションがまだダーティリードと呼ばれるデータが登録されていません読み込みます。

     たとえば、次のトランザクションのトランザクションBは、データ更新とロールバックBを読み出し、その後、読み出しデータがダーティデータであります

2、非反復可能読み取り

      同じトランザクション、同じデータを繰り返し矛盾して読み出します。

      例:トランザクションAは、同じデータを複数回読み込むトランザクションBが何回も読んで、取引の過程で、データは、トランザクションAが同じデータを複数回には一貫性のない結果につながる読み込み、更新され、提出されました。

3、ファントム読み取り

      同じトランザクション、同じ条件に従ってデータの量(すなわち個数)矛盾読み出しです。

     たとえば、次のトランザクションが多数回読み出し時、データが追加または削除が行われた後、トランザクション取引B、データ(例えば、年齢> = 10のような)多くを読み取る、複数その結果が同じトランザクションAの読み取り条件を満足しますデータ条件、データの矛盾の量。

     ここでは非反復可能読み取りとファントム読みの違いについて話をします:

  • しかし、不可重复读:主なポイントは、複数のレコードを読み込むことで、レコードはいくつかの列の値が変更されていました。
  • 幻读:主なポイントは、かつての範囲内で多くのレコードを読んで(結果を含むすべてのレコードに直接アクセス、または統計的な集計を行う)ことで、矛盾した結果が(一般的に標準ファイル・レコードの増加を意味し、レコードが読みファントムを減らすために考慮されるべきである)が発見

     また、私は私が誰でもMVCCのために詳細に説明し、次のMVCCののInnoDB MySQLは読ん私たちはファントムの問題を解決する助けている、ことを言及する必要があります。

第三に、物事の問題は、分離の異なるレベルを持っています

 MySQLのデフォルトの分離レベル:反復可能読み取り(反復可能読み取り)

分離レベル ダーティー読み取り        またとない度 マジック読書     
非コミット読み取り(読み取りコミットされていません) それはあります それはあります それはあります
コミット読み取り(読み取りコミット) ノー それはあります それはあります
反復可能読み取り(反復可能読み取り) ノー ノー それはあります
直列化(シリアライズ) ノー ノー ノー

 

 

 

 

 

第四に、分離レベルの詳細な例

 

1、非コミット読み取り(読み取りコミットされていない) - ダーティー読み取り

#首先,修改隔离级别
set tx_isolation='READ-UNCOMMITTED';
select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+

#事务A:启动一个事务
start transaction;
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |    1 |
|    2 |    2 |
|    3 |    3 |
+------+------+

#事务B:也启动一个事务(那么两个事务交叉了)
       在事务B中执行更新语句,且不提交
start transaction;
update tx set num=10 where id=1;
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |   10 |
|    2 |    2 |
|    3 |    3 |
+------+------+

#事务A:那么这时候事务A能看到这个更新了的数据吗?
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |   10 |   --->可以看到!说明我们读到了事务B还没有提交的数据
|    2 |    2 |
|    3 |    3 |
+------+------+

#事务B:事务B回滚,仍然未提交
rollback;
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |    1 |
|    2 |    2 |
|    3 |    3 |
+------+------+

#事务A:在事务A里面看到的也是B没有提交的数据
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |    1 |      --->脏读意味着我在这个事务中(A中),事务B虽然没有提交,但它任何一条数据变化,我都可以看到!
|    2 |    2 |
|    3 |    3 |
+------+------+

 

2、读已提交(read-committed)-- 不可重复读

#首先修改隔离级别
set tx_isolation='read-committed';
select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+

#事务A:启动一个事务
start transaction;
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |    1 |
|    2 |    2 |
|    3 |    3 |
+------+------+

#事务B:也启动一个事务(那么两个事务交叉了)
       在这事务中更新数据,且未提交
start transaction;
update tx set num=10 where id=1;
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |   10 |
|    2 |    2 |
|    3 |    3 |
+------+------+

#事务A:这个时候我们在事务A中能看到数据的变化吗?
select * from tx;
+------+------+                
| id   | num  |                
+------+------+                
|    1 |    1 |--->并不能看到!  
|    2 |    2 |                
|    3 |    3 |                
+------+------+                
                               
#事务B:如果提交了事务B呢?         
commit;                        
                               
#事务A:                         
select * from tx;
+------+------+
| id   | num  |
+------+------+
|    1 |   10 |----------------->相同的select语句,两次查询结果不一样
|    2 |    2 |
|    3 |    3 |
+------+------+

 

3、可重复读repeatable-read)-- 幻读

#首先,更改隔离级别
set tx_isolation='repeatable-read'; select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ #事务A:启动一个事务 start transaction; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +------+------+ #事务B:开启一个新事务(那么这两个事务交叉了)
       在事务B中更新数据,并提交 start transaction; update tx set num=10 where id=1; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +------+------+ commit; #事务A:这时候即使事务B已经提交了,但A能不能看到数据变化? select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | --->还是看不到的!(这个级别2不一样,也说明级别3解决了不可重复读问题) | 2 | 2 | | 3 | 3 | +------+------+ #事务A:只有当事务A也提交了,它才能够看到数据变化 commit; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +------+------+

 

4、可串行化(serializable)

 #首先修改隔离界别
set tx_isolation='serializable';
select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE   |
+----------------+

#事务A:开启一个新事务
start transaction;

#事务B:在A没有commit之前,这个交叉事务是不能更改数据的
start transaction;
insert tx values('4','4');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
update tx set num=10 where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

 

参考文章

    https://www.cnblogs.com/snsdzjlz320/p/5761387.html

 

おすすめ

転載: www.cnblogs.com/kukudexin/p/10965646.html