MySQL_REPEATABLE-READトランザクション独立性レベル
5316 ワード
MySQL_REPEATABLE-READトランザクション独立性レベル
このようなビジネスシナリオを考えると...
トランザクションA:ユーザー照会残高は4000元で、2000に保存され、データベースに書き込まれ、残高は6000元である.
事務B:銀行システムは月初めに、控除を行い、控除は500です.
テーブル文:
事務A
トランザクションAは、a=60のレコードを問合せ、a=60のレコードの値を6000に更新します.トランザクションはコミットされていません.の
対応した先のビジネスシーンは月初めに残高4000をベースに2000を預け、最終残高は6000...
事務B
事物Bでは,a=60のレコードをクエリし,値は4000,更新a=60のフィールド値は3500である.
先ほどの业务シーンに対応して月初めに银行が税金を引かなければならないので、残高4000の上で500を差し引いて、最终的に残高は3500になります...
事務A
トランザクションAがコミットされると、トランザクションBのブロックが消え、トランザクションAがレコードのwrite lockを解除します...
事務B
トランザクションBは、データを変更し、トランザクションをコミットする.
このとき、このユーザーは、残高を調べて、口座にいくら残っているかを見ます.
あと3500、なに!!!まあ、4000+2000だったのに、残高が3500になったなんて、これは大きな問題です.
では、このような状況を避けるにはどうすればいいのでしょうか.
基本的な考え方:修正された行に排他ロックを追加すると、排他ロックはリードロックとライトロックをブロックします.
事務A
預金4000+2000を完了する.トランザクションはコミットされていません.
事務B
このとき,A=51のレコードを事物Bで照会すると,4000の値が見られ,この残高に基づいて銀行が500の引き落としを行い,データベースにセットすると,以前にユーザが書き込んだ残高6000が上書きされる.
select * from t1 where a = 51; この文では、なぜデータをクエリーできるのでしょうか.なぜselect*from t 1 where a=51 lock in share mode;なぜブロックされるのか.
物事Aではa=51の記録に排他ロック(書き込みロック)が付加されており、このロックは他のリードロックや書き込みロックを排斥しており、lock in share modeはselectにリードロックが付加されていることを示しているので排斥されている.
前者のselectはレコードにロックをかけていないのに、mysqlのデフォルトのトランザクション・アイソレーション・レベルが繰り返し読み取り可能であるため、スナップショット・データが読み出されるため、ロックされたレコードが読み出されるのはなぜですか.
select * from t1 where a = 51 for update;そのレコードに書き込みロックがかかっているので、事務Aの書き込みロックに排斥されます.
時間が経過すると、次のようにロックがタイムアウトします.
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
下を見続けます.
事務A
トランザクションAがコミットされると、排他ロックは消えます.
事務B
トランザクションAがコミットされるとselect*from t 1 where a=51 for updateを通過できます.結果がクエリーされると、レコードに書き込みロック、すなわち排他ロックも追加されます.
控除操作6000-500を完了する.
この時、ユーザーはいくらを調べますか?
いいえ、6000ではありませんか.彼はまた口座の明細を調べて、月初めに引き落としたことを知りました.そう、最終残高は5500です.そうです.
=============END=============
このようなビジネスシナリオを考えると...
トランザクションA:ユーザー照会残高は4000元で、2000に保存され、データベースに書き込まれ、残高は6000元である.
事務B:銀行システムは月初めに、控除を行い、控除は500です.
テーブル文:
CREATE TABLE t1 (
a int not null,
b int not null,
PRIMARY KEY (a)
);
事務A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 ;
+----+------+
| a | b |
+----+------+
| 51 | 2000 |
| 52 | 1234 |
| 53 | 5999 |
| 54 | 5000 |
| 55 | 6000 |
| 56 | 7000 |
| 57 | 5000 |
| 60 | 4000 |
| 61 | 2000 |
+----+------+
9 rows in set (0.00 sec)
mysql> update t1 set b = 6000 where a = 60;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1 where a = 60;
+----+------+
| a | b |
+----+------+
| 60 | 6000 |
+----+------+
1 row in set (0.00 sec)
トランザクションAは、a=60のレコードを問合せ、a=60のレコードの値を6000に更新します.トランザクションはコミットされていません.の
対応した先のビジネスシーンは月初めに残高4000をベースに2000を預け、最終残高は6000...
事務B
mysql> begin ;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where a = 60;
+----+------+
| a | b |
+----+------+
| 60 | 4000 |
+----+------+
1 row in set (0.01 sec)
mysql> update t1 set b = 3500 where a = 60;
lock wait...
事物Bでは,a=60のレコードをクエリし,値は4000,更新a=60のフィールド値は3500である.
先ほどの业务シーンに対応して月初めに银行が税金を引かなければならないので、残高4000の上で500を差し引いて、最终的に残高は3500になります...
事務A
mysql> commit;
Query OK, 0 rows affected (0.07 sec)
トランザクションAがコミットされると、トランザクションBのブロックが消え、トランザクションAがレコードのwrite lockを解除します...
事務B
Query OK, 1 row affected (25.46 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1 where a = 60;
+----+------+
| a | b |
+----+------+
| 60 | 3500 |
+----+------+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.03 sec)
トランザクションBは、データを変更し、トランザクションをコミットする.
このとき、このユーザーは、残高を調べて、口座にいくら残っているかを見ます.
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where a = 60;
+----+------+
| a | b |
+----+------+
| 60 | 3500 |
+----+------+
1 row in set (0.00 sec)
mysql>
あと3500、なに!!!まあ、4000+2000だったのに、残高が3500になったなんて、これは大きな問題です.
では、このような状況を避けるにはどうすればいいのでしょうか.
基本的な考え方:修正された行に排他ロックを追加すると、排他ロックはリードロックとライトロックをブロックします.
事務A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where a = 51;
+----+------+
| a | b |
+----+------+
| 51 | 4000 |
+----+------+
1 row in set (0.00 sec)
mysql> select * from t1 where a = 51 for update;
+----+------+
| a | b |
+----+------+
| 51 | 4000 |
+----+------+
1 row in set (0.00 sec)
mysql> update t1 set b = 6000 where a = 51;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1 where a = 51;
+----+------+
| a | b |
+----+------+
| 51 | 6000 |
+----+------+
1 row in set (0.00 sec)
預金4000+2000を完了する.トランザクションはコミットされていません.
事務B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where a = 51;
+----+------+
| a | b |
+----+------+
| 51 | 4000 |
+----+------+
1 row in set (0.00 sec)
mysql> select * from t1 where a = 51 lock in share mode;
Ctrl-C -- sending "KILL QUERY 2" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from t1 where a = 51 for update;
......................
このとき,A=51のレコードを事物Bで照会すると,4000の値が見られ,この残高に基づいて銀行が500の引き落としを行い,データベースにセットすると,以前にユーザが書き込んだ残高6000が上書きされる.
select * from t1 where a = 51; この文では、なぜデータをクエリーできるのでしょうか.なぜselect*from t 1 where a=51 lock in share mode;なぜブロックされるのか.
物事Aではa=51の記録に排他ロック(書き込みロック)が付加されており、このロックは他のリードロックや書き込みロックを排斥しており、lock in share modeはselectにリードロックが付加されていることを示しているので排斥されている.
前者のselectはレコードにロックをかけていないのに、mysqlのデフォルトのトランザクション・アイソレーション・レベルが繰り返し読み取り可能であるため、スナップショット・データが読み出されるため、ロックされたレコードが読み出されるのはなぜですか.
select * from t1 where a = 51 for update;そのレコードに書き込みロックがかかっているので、事務Aの書き込みロックに排斥されます.
時間が経過すると、次のようにロックがタイムアウトします.
mysql> select * from t1 where a = 51 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
下を見続けます.
事務A
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
トランザクションAがコミットされると、排他ロックは消えます.
事務B
トランザクションAがコミットされるとselect*from t 1 where a=51 for updateを通過できます.結果がクエリーされると、レコードに書き込みロック、すなわち排他ロックも追加されます.
....... , ........
+----+------+
| a | b |
+----+------+
| 51 | 6000 |
+----+------+
1 row in set (21.75 sec)
mysql> update t1 set b = 5500 where a = 51;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
控除操作6000-500を完了する.
この時、ユーザーはいくらを調べますか?
mysql> begin ;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where a = 51;
+----+------+
| a | b |
+----+------+
| 51 | 5500 |
+----+------+
1 row in set (0.00 sec)
いいえ、6000ではありませんか.彼はまた口座の明細を調べて、月初めに引き落としたことを知りました.そう、最終残高は5500です.そうです.
=============END=============