Skip to content
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

Merged
merged 10 commits into from
Jun 25, 2021

Conversation

kamimi01
Copy link
Owner

@kamimi01 kamimi01 commented May 2, 2021

対応内容

以下の対応を行いました。

  • 課題21

依頼事項

以下のご確認をお願い致します。

関連リンク

  • 課題のファイル名とリンク

その他

  • 可能な範囲で、、ご確認お願いいたします!🙇‍♂️

Closes #67

@kamimi01 kamimi01 requested a review from shimopino May 2, 2021 03:11
@kamimi01 kamimi01 self-assigned this May 2, 2021
@kamimi01 kamimi01 added this to In progress (Not in review) in PrAha Challenge課題管理 via automation May 2, 2021
Copy link
Collaborator

@shimopino shimopino left a 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)
Copy link
Collaborator

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 においては、自動的にデッドロック状態を検出し、影響があるいずれかのトランザクションをロールバックする。デッドロックは複数のスレッドが同じロックの取得を待機している状態なため、処理遅延の要因となる。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回試してないんですが、デッドロック検知によるオーバーヘッドが問題になるケースはあるのか気になりました 🤔

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MySQL8.0のデッドロック 検出に関しての記述

| ------------------ | ---------------------------------- | ---- |
| 行ロック | ある特定の 1 行のみをロックする | |
| テーブルロック | ある特定のテーブル全体をロックする | |
| データベースロック | データベース全体をロックする | |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

データベースロックというのみあるんですね...(初めて知った...)

MySQLで実現できるのかはわからなかったんですが、以下にIBMの資料を載せておきます!

Copy link
Collaborator

@shimopino shimopino May 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Owner Author

@kamimi01 kamimi01 May 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DB2のロックエスカレーションについて


| ロックの厳しさ | 概要 | 備考 |
| ------------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------------- |
| 共有ロック | 他のトランザクションからのデータの参照は可能だが、更新は不可能。<br> | 通常、SELECT 文で選択した行には自動的に共有ロックがかかる。 |
Copy link
Collaborator

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)

Copy link
Collaborator

@shimopino shimopino May 2, 2021

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     |
+--------+---------------+-------------+------------+-----------+---------------+-------------+-----------+

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます!この文章はMySQLのみに限った話ではなかったですが、MySQLの場合はかからないという感じですね。。。!

- テーブルロックのメリット
- 必要なメモリが比較的少なくなる
- 単一のロックだけが必要なため、テーブルの大部分に対して使用する場合には高速
- データの大部分に対して GROUP BY を頻繁に実行する場合や、テーブル全体を頻繁にスキャンする必要がある場合に高速
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こういうユースケースがあるんですね!

Comment on lines +90 to +91
|悲観ロック|データそのものはロックせず、更新対象のデータがデータ取得時と同じ状態であることを確認してから更新することで、データの整合性を保証する方式。その確認のために、Versionを管理するためのカラムをもうけて(ロックキーと呼ばれる)、データ取得時のVersionとデータ更新時のVersionを比較する。|Versionのカラム以外にもタイムスタンプを保持する方法もあるが、より精度の高いミリ秒まで保持していたとしても、同時に複数の操作が行われているかの見極めが困難なため、タイムスタンプをロックキーとすることはあまり推奨されていない。|
|楽観ロック|更新対象のデータを取得する前にロックをかけることで、他のトランザクションから更新されないようにする方式。トランザクション開始直後に更新対象となるレコードのロックを取得する。ロックされたレコードはトランザクションがコミットまたはロールバックされるまで、データの整合性を保証することができる。|`SELECT~ FOR UPDATE`文が利用されることが多い。確実にロックを開放するのが難しいため、ロック状態が長く続くなど発生した場合の回避策が必要。|
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここに関して「楽観ロック」と「悲観ロック」の説明文が反対になっていると思います!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちなみに自分は「楽観ロック」を使ったことがありません!

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここに関して「楽観ロック」と「悲観ロック」の説明文が反対になっていると思います!

逆でした。。!ご指摘ありがとうございます!

Copy link
Owner Author

@kamimi01 kamimi01 May 2, 2021

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;`を実行することでオフにもできる。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「十国」→「実行」でしょうか

Copy link
Owner Author

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コミットモードはJDBCだとこう設定できるんですね!

ありがとうございます

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

普段の業務だと自社製のフレームワークを使っているので、あまりJDBCの細かい部分は意識したことがないんですよね...

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私は生のJDBCしか見たことがなく。。。
こんなの見たなと思って、載せてみました!

Copy link
Collaborator

@shimopino shimopino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

課題2のコメントを追加しました~

気になる部分があったのでコメントしてますー

Comment on lines +78 to +86
# この段階でターミナル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)
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

グローバル設定でトランザクションの分離レベルを設定していれば、ターミナルにログインした段階で未コミット状態のデータが見えるんですね。
(自分は実験ごとにセッションで分離レベルを設定していました。)

Comment on lines +137 to +144
# ターミナル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)
Copy link
Collaborator

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 文の実行は同一のトランザクション内での処理になるのでしょうか 🤔

Copy link
Owner Author

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;する必要がある

Copy link
Collaborator

@shimopino shimopino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

クイズの回答を追加しました!

自分が調査を後回しにしていた機能に関するクイズもあり勉強になりました!
ありがとうございます!!


## クイズ2

- MySQLでは、行ロックが解除されるまでInnoDBが待機する時間を定義するシステム変数が存在します。その変数はなんでしょうか?
Copy link
Collaborator

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秒で設定可能)

参考資料

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます!こちらで回答OKです

Comment on lines +17 to +18
- MySQL8.0以降では、ロックに関して`NOWAIT`と`SKIP LOCKED`の機能が新たに追加されました。
- この2つがどんな機能か調べてみましょう。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 背景
    • MySQL5.7以前では、トランザクション内でロックを取得する処理を実行した際に、対象レコードがほかのトランザクションにロックされている場合に、行ロックが解放されるまで待機する必要があった
    • 途中でステートメントを終了させるような機能は提供されていなかった
  • 変更点
    • MySQL8.0から、ロックの取得時に NOWAITSKIP LOCKED を設定できるようになった
    • NOWAIT
      • 対象レコードがすでにロックされている場合にはステートメントをすぐに終了させる
    • SKIP LOCKED
      • ロックされたレコードを除外しても問題ない場合は、ロックの解放を待機せずに抽出できた結果セットのみを返す

参考資料

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SKIP LOCKEDの使いどころは、2つ目の参考資料で提示されている事例がわかりやすかったです。

ユーザーがチケットを購入する際に、チケットレコードの user_idNULL の値を、ユーザーの先着順で対応する user_id で上書きする処理
この場合は、確かに複数枚存在するチケットの中からどれか1つを取得できればいいため、すでにロックがかかっているレコードは結果セットから除外してもよさそう

@shimopino
Copy link
Collaborator

shimopino commented May 2, 2021

(課題内容とは直接関係ないんですが...)
今回のプルリクから、課題の採番は -1 していく感じでしょうか

@kamimi01 kamimi01 changed the title 課題21「トランザクションについて理解する」の対応完了 課題22「トランザクションについて理解する」の対応完了 May 2, 2021
@kamimi01 kamimi01 merged commit c72208f into develop Jun 25, 2021
PrAha Challenge課題管理 automation moved this from In progress (Not in review) to Done Jun 25, 2021
@kamimi01 kamimi01 deleted the feature/task-21-understand-transaction branch June 25, 2021 00:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

2 participants