Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
多重登録を防御するためのノウハウ
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Ryohei KOMATSUYAMA
May 15, 2024
Programming
260
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
多重登録を防御するためのノウハウ
2024/05/15【DMM×バイセル】若手エンジニアによる学生向けTech Study Summit
Ryohei KOMATSUYAMA
May 15, 2024
Other Decks in Programming
See All in Programming
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
200
Lessons from Spec-Driven Development
simas
PRO
0
170
AI時代のUIはどこへ行く?その2!
yusukebe
21
7k
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
120
Oxlintのカスタムルールの現況
syumai
6
1.1k
Composerを使ったサプライチェーン攻撃の様子を眺めてみる #phpstudy
o0h
PRO
2
240
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
3
1.3k
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
1
660
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
Spec-Driven Development with AI-Agents: From High-Level Requirements to Working Software
antonarhipov
2
490
OSもどきOS
arkw
0
480
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
150
Featured
See All Featured
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Documentation Writing (for coders)
carmenintech
77
5.4k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
Exploring anti-patterns in Rails
aemeredith
3
400
Navigating Team Friction
lara
192
16k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.2k
Become a Pro
speakerdeck
PRO
31
6k
4 Signs Your Business is Dying
shpigford
187
22k
Transcript
多重登録を防御するためのノウハウ 2024/05/15 【DMM×バイセル】若手エンジニアによる学生向けTech Study Summit 小松山凌平
👓 小松山 凌平 👶 1998/09/09 生 (2021 年卒) 🏢 開発
1 部 Cosmos 基盤グループ 🧻 BE メインのエンジニア 🏀 NBA 観戦 🧌 Monster Hunter World 🙅 x.com/kmtym_dev zenn.dev/kmtym1998 2 自己紹介
多重登録をデータベースレベルで防御できると安心です API 実装の際の手札を増やしてもらいたいです (PostgreSQL を前提とした話をします) 3 今日のメッセージ
• 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ 4 話すこと
• 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ 5 話すこと
• とあるシステムのユーザ管理機能を例にする • ユーザが持つ情報 ◦ ユーザID ◦ 名前 ◦ メールアドレス
◦ ステータス (招待済 / 登録済 / 削除済 の 3 値をとる) • ユーザに関する制約 ◦ "招待済" "登録済" のユーザはメールアドレスが重複しない 6 説明のための例 (要件)
7 説明のための例 (テーブル定義) カラム名 カラムの型 制約 id serial PRIMARY KEY,
NOT NULL name text NOT NULL email text NOT NULL status enum NOT NULL • テーブル名: users • users.status の取り得る値は 'INVITED' / 'REGISTERED' / 'DELETED' の 3 値
8 • 招待者のダブルサブミットによって 招待済ユーザが 2 人できてしまった • 一応重複チェックはしていたつもり ◦ メールアドレスが一致
&& "削除済" でない ユーザがいるか検索 ◦ 検索して見つからなければ新規にレコード作成 • ダブルサブミットによってリクエストが 並列に処理され、ロジックをすり抜けた 多重登録によるトラブル エラーハンドリング等は省略しています
• 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ 9 話すこと
10 多重登録を防ぐためのアプローチ • トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける
• トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける 11 多重登録を防ぐためのアプローチ
• 同時に複数のトランザクションが発生したときの挙動を決めるオプション • 標準 SQL で定められているものが以下の 4 つ (下に行くほど分離性が強い) ◦
リードアンコミッティド ◦ リードコミッティド (PostgreSQL のデフォルトはこれ) ◦ リピータブルリード (MySQL のデフォルトはこれ) ◦ シリアライザブル 12 トランザクション分離レベルとは・・・ PostgreSQLでの挙動
• 同時に複数のトランザクションが発生したときの挙動を決めるオプション • 標準 SQL で定められているものが以下の 4 つ (下に行くほど分離性が強い) ◦
リードアンコミッティド ◦ リードコミッティド (PostgreSQL のデフォルトはこれ) ◦ リピータブルリード (MySQL のデフォルトはこれ) ◦ シリアライザブル 13 トランザクション分離レベルとは・・・ PostgreSQLでの挙動
デフォルトの分離レベルがデータベース 単位で決まっている (変更可能) 14 トランザクション分離レベルの指定 トランザクション開始時に個別で設定も可能
シリアライザブル分離レベルは、最も厳しいトランザクションの分離性を提供します。このレベルでは トランザクションが同時にではなく、次から次へと、あたかも順に実行されているように逐次的な トランザクションの実行を全てのコミットされたトランザクションに対しエミュレートします。 PostgreSQL 15.4 文書 - 13.2 トランザクション分離 15
トランザクション分離レベル: シリアライザブル トランザクションの直列性を保証したいときに使う ※ ただし、相対的にパフォーマンスは悪くなる
16 TX開始 重複チェック ユーザ登録 コミット TX開始 重複チェック ユーザ登録 コミット 並列検出🔎
TX開始 重複チェック ユーザ登録 コミット TX開始 重複チェック ロールバック 成功 ✅ 成功 ✅ 重複検出🔎 直列なトランザクション 並列なトランザクション
17 多重登録を防ぐためのアプローチ • トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける
• 複数のトランザクションから同時に同じデータを 操作させないようにするための仕組み • トランザクション A がロックをかけているとき、 トランザクション B がロックをかけようとすると
A が解放されるまで B は待たされる • 重複チェックの前にロックをかける 18 テーブルロックとは・・・
19 別のトランザクションはロック解放を待つ TX開始 重複チェック ユーザの登録 コミット 成功 ✅ ロック 重複チェック
TX開始 ロック ロックの解放待ち 重複検出🔎 ※ 分離レベルはリードアンコミッティド・リードコミッティドを使う
20 • トランザクション分離レベルが高すぎると正しく重複チェックできない ◦ 並列して発生したトランザクションで作成されたレコードを読み取る必要がある ◦ リードアンコミッティド・リードコミッティドを使う • デッドロックに気を配る ◦
トランザクションが互いのロック解放を待つ状態となってしまい、いずれの処理も 止まってしまう状態 ◦ ロック時間の上限を設けておくなどして回避する • レコードロックでは重複登録は防げない 注意点
21 多重登録を防ぐためのアプローチ • トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける
22 部分インデックスとは・・・ 部分インデックスとは、テーブルの部分集合に構築されるインデックスです。 部分集合は、(部分イン デックスの述語と呼ばれる)条件式で定義されます。 部分インデックスには、その述語を満たすテーブ ル行のみに対するエントリが含まれます。 PostgreSQL 15.4 文書
- 11.8. 部分インデックス 普通のインデックス 部分インデックス ※ サポートがない RDBMS もある
23 部分インデックスのあるテーブルへの INSERT id status email 1 REGISTERED
[email protected]
2
REGISTERED
[email protected]
3 INVITED
[email protected]
4 INVITED
[email protected]
5 DELETED
[email protected]
id status email 1 REGISTERED
[email protected]
2 REGISTERED
[email protected]
3 INVITED
[email protected]
4 INVITED
[email protected]
5 DELETED
[email protected]
インデックスの範囲 インデックスの範囲 普通のインデックス 部分インデックス
インデックスの範囲 24 部分インデックスのあるテーブルへの INSERT id status email 1 REGISTERED
[email protected]
2 REGISTERED
[email protected]
3 INVITED
[email protected]
4 INVITED
[email protected]
5 DELETED
[email protected]
6 INVITED
[email protected]
id status email 1 REGISTERED
[email protected]
2 REGISTERED
[email protected]
3 INVITED
[email protected]
4 INVITED
[email protected]
5 DELETED
[email protected]
6 INVITED
[email protected]
インデックスの範囲 🙅 🙆 普通のインデックス 部分インデックス
25 部分インデックスのパフォーマンス (1)のグラフより、部分インデックスが定義されている条件であれば、通常のインデックスと部分イン デックスで実行速度に差がないことを確認できました。 (2)のグラフより、部分インデックスが定義されていない条件では、当然ですが通常のインデックスの 方が部分インデックスよりも高速に実行されます。 (※ B-Tree インデックスの場合) 株式会社インサイト
TECH BLOG - 部分インデックスの効果を検証(1)
26 話すこと • 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ
• 忘れがちですが、多重登録はサーバ側で守れると安心です ◦ データベースレベルで防御できると堅牢になります • 重複チェックをするための方法を 3 つ紹介しました ◦ トランザクション分離レベルを上げる方法
◦ テーブルロックを使う方法 ◦ 部分インデックスを使う方法 • 同じような話を記事にしているので良ければご覧ください 27 まとめ
ありがとうございました