-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
課題22「トランザクションについて理解する」の対応完了 #68
Conversation
…ub.com/kamimi01/praha_challenge_tasks into feature/task-21-understand-transaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
課題1へのコメントを追加しました~
- 同じ順番でロックする | ||
- デッドロックは相手と異なる順番でロックを行おうとする場合に発生するため。 | ||
|
||
![](https://cloudear.jp/blog/wp-content/uploads/2015/07/deadlock2.png) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この図わかりやすいですね
(今回いろいろ作図をしてみたので、色遣いなど参考になります)
- データベースで同時に複数のトランザクションが実行される場合に、起こる可能性がある。 | ||
- テーブル A のロックを取得したトランザクション 1 が、次にテーブル B のロックも取得しようとしている。その一方でテーブル B のロックを取得してトランザクション 2 がテーブル A のロックを取得しようとしている状態。お互いがそれぞれ次にロックを取得したいテーブルのロックの解除を待機する状態になり、トランザクションの処理が止まってしまう。 | ||
- DBMS は、自動的にデッドロック状態を検出し、デッドロック状態から抜け出すための仕組みが用意されている | ||
- MySQL においては、自動的にデッドロック状態を検出し、影響があるいずれかのトランザクションをロールバックする。デッドロックは複数のスレッドが同じロックの取得を待機している状態なため、処理遅延の要因となる。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
今回試してないんですが、デッドロック検知によるオーバーヘッドが問題になるケースはあるのか気になりました 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MySQL8.0のデッドロック 検出に関しての記述
| ------------------ | ---------------------------------- | ---- | | ||
| 行ロック | ある特定の 1 行のみをロックする | | | ||
| テーブルロック | ある特定のテーブル全体をロックする | | | ||
| データベースロック | データベース全体をロックする | | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DB2のロックエスカレーションについて
|
||
| ロックの厳しさ | 概要 | 備考 | | ||
| ------------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------------- | | ||
| 共有ロック | 他のトランザクションからのデータの参照は可能だが、更新は不可能。<br> | 通常、SELECT 文で選択した行には自動的に共有ロックがかかる。 | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SELECT
文の実行時にロックがかかるということは、以下の実行時に瞬間的にロックがかかっているというイメージであってますかね...
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from employees where emp_no IN (10001, 10002, 10003);
+--------+------------+---------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+---------------+-----------+--------+------------+
| 10001 | 1953-09-02 | Georgi Georgi | Facello | M | 1986-06-26 |
| 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 |
| 10003 | 1959-12-03 | Parto | Bamford | M | 1986-08-28 |
+--------+------------+---------------+-----------+--------+------------+
3 rows in set (0.01 sec)
-- ここでロックが一瞬かかっている?
mysql> SELECT engine, object_schema, object_name, index_name, lock_type, lock_mode, lock_status, lock_data FROM performance_schema.data_locks;
Empty set (0.00 sec)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FOR SHARE
の結果です。
mysql> SELECT engine, object_schema, object_name, index_name, lock_type, lock_mode, lock_status, lock_data FROM performance_schema.data_locks;
+--------+---------------+-------------+------------+-----------+---------------+-------------+-----------+
| engine | object_schema | object_name | index_name | lock_type | lock_mode | lock_status | lock_data |
+--------+---------------+-------------+------------+-----------+---------------+-------------+-----------+
| INNODB | employees | employees | NULL | TABLE | IS | GRANTED | NULL |
| INNODB | employees | employees | PRIMARY | RECORD | S,REC_NOT_GAP | GRANTED | 10002 |
| INNODB | employees | employees | PRIMARY | RECORD | S,REC_NOT_GAP | GRANTED | 10003 |
| INNODB | employees | employees | PRIMARY | RECORD | S,REC_NOT_GAP | GRANTED | 10001 |
+--------+---------------+-------------+------------+-----------+---------------+-------------+-----------+
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます!この文章はMySQLのみに限った話ではなかったですが、MySQLの場合はかからないという感じですね。。。!
- テーブルロックのメリット | ||
- 必要なメモリが比較的少なくなる | ||
- 単一のロックだけが必要なため、テーブルの大部分に対して使用する場合には高速 | ||
- データの大部分に対して GROUP BY を頻繁に実行する場合や、テーブル全体を頻繁にスキャンする必要がある場合に高速 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こういうユースケースがあるんですね!
|悲観ロック|データそのものはロックせず、更新対象のデータがデータ取得時と同じ状態であることを確認してから更新することで、データの整合性を保証する方式。その確認のために、Versionを管理するためのカラムをもうけて(ロックキーと呼ばれる)、データ取得時のVersionとデータ更新時のVersionを比較する。|Versionのカラム以外にもタイムスタンプを保持する方法もあるが、より精度の高いミリ秒まで保持していたとしても、同時に複数の操作が行われているかの見極めが困難なため、タイムスタンプをロックキーとすることはあまり推奨されていない。| | ||
|楽観ロック|更新対象のデータを取得する前にロックをかけることで、他のトランザクションから更新されないようにする方式。トランザクション開始直後に更新対象となるレコードのロックを取得する。ロックされたレコードはトランザクションがコミットまたはロールバックされるまで、データの整合性を保証することができる。|`SELECT~ FOR UPDATE`文が利用されることが多い。確実にロックを開放するのが難しいため、ロック状態が長く続くなど発生した場合の回避策が必要。| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここに関して「楽観ロック」と「悲観ロック」の説明文が反対になっていると思います!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ちなみに自分は「楽観ロック」を使ったことがありません!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここに関して「楽観ロック」と「悲観ロック」の説明文が反対になっていると思います!
逆でした。。!ご指摘ありがとうございます!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PrismaのDBトランザクションについて
- 上記の状態になるよう制御するための仕組み。 | ||
- コミット | ||
- トランザクションが終了する際に、トランザクション中の SQL 文によって行われた処理を確定すること | ||
- 多くの DBMS では、自動コミットモードがオンの状態で動作するため、1 つのクエリが十国されるたびに自動でコミットを実行する。アプリケーションの実装でオフにすることが可能。(下記に Java のコードあり)MySQLでは`SET AUTOCOMMIT=0;`を実行することでオフにもできる。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
「十国」→「実行」でしょうか
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
実行です。。
try (Connection db = DriverManager.getConnection( | ||
"jdbc:mysql:⁄⁄localhost/sample?serverTimezone=JST&useUnicode=true&characterEncoding=UTF-8&useSSL=true", "root", "12345")) { | ||
// 自動コミットモードをオフ | ||
db.setAutoCommit(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
コミットモードはJDBCだとこう設定できるんですね!
ありがとうございます
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
普段の業務だと自社製のフレームワークを使っているので、あまりJDBCの細かい部分は意識したことがないんですよね...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
私は生のJDBCしか見たことがなく。。。
こんなの見たなと思って、載せてみました!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
課題2のコメントを追加しました~
気になる部分があったのでコメントしてますー
# この段階でターミナル2で以下を実行 | ||
mysql> select * from titles where emp_no = 499942; | ||
+--------+------------------+------------+------------+ | ||
| emp_no | title | from_date | to_date | | ||
+--------+------------------+------------+------------+ | ||
| 499942 | Technique Leader | 1998-03-28 | 2021-05-02 | # コミットされていない変更を見ることができている→ダーティリード | ||
+--------+------------------+------------+------------+ | ||
1 row in set (0.00 sec) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
グローバル設定でトランザクションの分離レベルを設定していれば、ターミナルにログインした段階で未コミット状態のデータが見えるんですね。
(自分は実験ごとにセッションで分離レベルを設定していました。)
# ターミナル1で再度検索する | ||
mysql> select * from titles where emp_no = 499942; | ||
+--------+------------------+------------+------------+ | ||
| emp_no | title | from_date | to_date | | ||
+--------+------------------+------------+------------+ | ||
| 499942 | Technique Leader | 1998-03-28 | 2021-05-02 | # 前回と異なる結果となった→Non-repeatable read | ||
+--------+------------------+------------+------------+ | ||
1 row in set (0.00 sec) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ふとした疑問なんですが、ターミナル1で START TRANSACTION
を宣言していない場合、ターミナル1で最初に行った SELECT
文の実行と、2回目の SELECT
文の実行は同一のトランザクション内での処理になるのでしょうか 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
autocommitがONの状態で実行しているため、別のトランザクションの処理となってしまっている
ターミナル1でもstart transaction;
する必要がある
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
クイズの回答を追加しました!
自分が調査を後回しにしていた機能に関するクイズもあり勉強になりました!
ありがとうございます!!
|
||
## クイズ2 | ||
|
||
- MySQLでは、行ロックが解除されるまでInnoDBが待機する時間を定義するシステム変数が存在します。その変数はなんでしょうか? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- システム変数
innodb_lock_wait_timeout
- トランザクションが行ロックを行う際の待機時間を設定可能
- デフォルトは50秒 (1秒~1073741824秒で設定可能)
参考資料
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます!こちらで回答OKです
- MySQL8.0以降では、ロックに関して`NOWAIT`と`SKIP LOCKED`の機能が新たに追加されました。 | ||
- この2つがどんな機能か調べてみましょう。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 背景
- MySQL5.7以前では、トランザクション内でロックを取得する処理を実行した際に、対象レコードがほかのトランザクションにロックされている場合に、行ロックが解放されるまで待機する必要があった
- 途中でステートメントを終了させるような機能は提供されていなかった
- 変更点
- MySQL8.0から、ロックの取得時に
NOWAIT
やSKIP LOCKED
を設定できるようになった NOWAIT
- 対象レコードがすでにロックされている場合にはステートメントをすぐに終了させる
SKIP LOCKED
- ロックされたレコードを除外しても問題ない場合は、ロックの解放を待機せずに抽出できた結果セットのみを返す
- MySQL8.0から、ロックの取得時に
参考資料
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SKIP LOCKED
の使いどころは、2つ目の参考資料で提示されている事例がわかりやすかったです。
ユーザーがチケットを購入する際に、チケットレコードの
user_id
がNULL
の値を、ユーザーの先着順で対応するuser_id
で上書きする処理
この場合は、確かに複数枚存在するチケットの中からどれか1つを取得できればいいため、すでにロックがかかっているレコードは結果セットから除外してもよさそう
(課題内容とは直接関係ないんですが...) |
対応内容
以下の対応を行いました。
依頼事項
以下のご確認をお願い致します。
関連リンク
その他
Closes #67