• Like
My sqlで遭遇したトランザクションとロックのお話
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

My sqlで遭遇したトランザクションとロックのお話

  • 65 views
Published

RDBMSのトランザクション、楽観ロック、悲観ロックがわかっている人向けのお話。 …

RDBMSのトランザクション、楽観ロック、悲観ロックがわかっている人向けのお話。
並行で処理が走っていて、同時にトランザクションが走った時、データベースから取得できる値がどうなるか?というお話

Published in Engineering
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
65
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. MySQLで遭遇したトランザクショ ンとロックのお話 小林拓
  • 2. 基本構成 ロードバランサ アプリケーション サーバ DBサーバ ……
  • 3. 基本構成 ロードバランサ アプリケーション サーバ DBサーバ …… この部分のお話
  • 4. 例(Rails) Id money 1 400 User.transaction do user = User.lock.find_by(id: 1) user.money += 400 user.save! end BEGIN; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET users.money = 800 WHERE id = 1; COMMIT; usersテーブル 悲観ロック
  • 5. 例の問題 リクエスト リクエスト BEGIN; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET users.money = 800 WHERE id = 1; COMMIT; BEGIN; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET users.money = ? WHERE id = 1; COMMIT; この値はいくつで しょう? 悲観ロックなので待ちます 同時
  • 6. 例の答え リクエスト リクエスト BEGIN; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET users.money = 800 WHERE id = 1; COMMIT; BEGIN; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET users.money = 800 WHERE id = 1; COMMIT このselect文では user.money = 400 が取得されている
  • 7. トランザクション分離レベル • READ UNCOMMITED • READ COMMITED • REPEATABLE READ • SERIALLIZABLE <= Oracle, PostgreSQL, SQL Severのデフォルト <= MySQLのデフォルト 参考: http://d.hatena.ne.jp/fat47/20140212/1392171784 下に行くほど不都合な読み込み現象が発生しなくなるが、 パフォーマンスが落ちる
  • 8. 対応 user = User.find_by(id: 1) User.transaction do user.lock! user.money += 400 user.save! end 必ずtransactionの外で一度select文を走らせ てデータをとるようにしましょう!! 修正後のコード REPEATABLE READではトランザクションが開 始された時点で参照される値は同じになる
  • 9. NGなコード users = User.where (id: 1) User.transaction do users.each do |user| user.money += 400 user.save! end end Id money lock_version 1 400 0 User.transaction do user = User. find_by(id: 1) user.money += 400 user.save! end 楽観ロック その2 その1 楽観ロックの意味がない SQLがでるのはここ