8. ロックとは?
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 8
empno ename sal
101 Nishida 500000
102 Nohira 285000
103 Kiyama 245000
T1 T2
複数のトランザクションから同時に実行された
とき、データの不整合が起こらないように行・表
・DBにロックをかける、DBMSの機能
○ ×
9. ロックなしの場合に起こる不整合
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 9
empno ename sal
101 Nishida 500000
102 Nohira 285000
103 Kiyama 245000
本当は520000
にならないと
おかしい!
2つのトランザクションか
ら同時に、empno=101
のsalを10000プラスする
① T1:101のsalを検索
(500000)
② T2:101のsalを検索
(500000)
③ T1:salを①+10000に更
新(510000)
④ T2:salを②+10000に更
新(510000)
17. 参考資料
Java EE 7 Tutorial
42. Controlling Concurrent Access to
Entity Data With Rocking
JSR-338 Java Persistence 2.1
3.4 Locking and Concurrency
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 17
25. スレッドクラス
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 25
System.out.println(threadName + " 終了 " + emp);
manager.close();
factory.close();
}
}
26. メインクラス
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 26
public class Main {
public static void main(String[] args) {
Thread thread1 = new UpdateThread();
thread1.setName("T1");
Thread thread2 = new UpdateThread();
thread2.setName("T2");
thread1.start();
thread2.start();
}
}
マルチスレッドで
同時実行
32. OPTIMISTICの実行ログ
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 32
[EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?)
bind => [101]
[EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?)
bind => [101]
T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
[EL Fine]: sql: UPDATE EMP2 SET SAL = ?, VERSION = ? WHERE ((EMPNO = ?) AND
(VERSION = ?)) bind => [510000, 2, 101, 1]
[EL Fine]: sql: UPDATE EMP2 SET SAL = ?, VERSION = ? WHERE ((EMPNO = ?) AND
(VERSION = ?)) bind => [510000, 2, 101, 1]
T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T1 commit.
T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T2 例外発生:javax.persistence.OptimisticLockException
T2 rollback.
T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
(以下、スタックトレース)
33. 実行の様子
① T1が検索→sal=500000, version=1
② T2が検索→sal=500000, version=1
③ T1がsal=500000+10000, version=1+1
で更新→コミット
④ T2がsal=500000+10000, version=1+1
で更新
→バージョンの値が既に変更されているため、
OptimisticLockExceptionが発生してロー
ルバック
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 33
34. 実行後のバージョン値
ロールバックされたエンティティも、バージョン値
がインクリメントされる
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 34
T1 commit.
T1 commit直後 Emp2 [empno=101, ename=Nishida,
sal=510000, version=2]
T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000,
version=2]
T2 例外発生:javax.persistence.OptimisticLockException
T2 rollback.
T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000,
version=2]
45. PESSIMISTIC_FORCE_INCREMENTの実行ログ
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 45
[EL Fine]: sql:SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR
UPDATE bind => [101]
[EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?)
FOR UPDATE bind => [101]
T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
[EL Fine]: sql: UPDATE EMP2 SET SAL = ?, VERSION = ? WHERE ((EMPNO = ?) AND
(VERSION = ?)) bind => [510000, 2, 101, 1]
T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T1 commit.
T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=2]
[EL Fine]: sql: UPDATE EMP2 SET SAL = ?, VERSION = ? WHERE ((EMPNO = ?) AND
(VERSION = ?)) bind => [520000, 3, 101, 2]
T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=3]
T2 commit.
T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=3]
T2 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=3]
46. 実行の様子
① T1が検索、WRTIEロックを取得
→sal=500000, version = 1
② T2が検索しようとするが、T1がWRITEロックを取
得しているので、DB内の待ち行列に入る
③ T1がsal=500000+10000, version=1+1で更新
→コミットしたらロック解放
④ T2が待ち行列から出て検索、WRITEロックを取得
→sal=510000, version=2
⑤ T2がsal=510000+10000, version=2+1で更新
→コミットしたらロック解放
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 46
63. OPTIMISTIC_FORCE_INCREMENTの実行ログ
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 63
Hibernate: select emp2x0_.empno as empno1_0_0_, emp2x0_.ename as ename2_0_0_,
emp2x0_.sal as sal3_0_0_, emp2x0_.version as version4_0_0_ from Emp2 emp2x0_ where
emp2x0_.empno=?
Hibernate: select emp2x0_.empno as empno1_0_0_, emp2x0_.ename as ename2_0_0_,
emp2x0_.sal as sal3_0_0_, emp2x0_.version as version4_0_0_ from Emp2 emp2x0_ where
emp2x0_.empno=?
T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=? and version=?
Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=? and version=?
T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
Hibernate: update Emp2 set version=? where empno=? and version=?
T1 例外発生:javax.persistence.OptimisticLockException
T2 commit.
T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]
T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]
T1 rollback.
T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
64. 実行後のバージョン値
flush時・commit時の2回、バージョンがインクリメントされ
る
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 64
T2 flush直前 Emp2 [empno=101, ename=Nishida,
sal=510000, version=1]
Hibernate: update Emp2 set ename=?, sal=?, version=?
where empno=? and version=?
T2 flush直後 Emp2 [empno=101, ename=Nishida,
sal=510000, version=2]
Hibernate: update Emp2 set version=? where empno=? and
version=?
T2 commit.
T2 commit直後 Emp2 [empno=101, ename=Nishida,
sal=510000, version=3]
65. PESSIMISTIC_READ
SELECT・・・LOCK IN SHARE MODE文が実行さ
れ、READロックが取得される
→T1とT2が互いにロック解放待ちとなり、
デッドロック発生
→片方はロールバックされ、
もう片方のみがコミットされる
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 65
66. PESSIMISTIC_READの実行ログ
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 66
Hibernate: select emp2x0_.empno as empno1_0_0_, emp2x0_.ename as ename2_0_0_,
emp2x0_.sal as sal3_0_0_, emp2x0_.version as version4_0_0_ from Emp2 emp2x0_ where
emp2x0_.empno=? lock in share mode
Hibernate: select emp2x0_.empno as empno1_0_0_, emp2x0_.ename as ename2_0_0_,
emp2x0_.sal as sal3_0_0_, emp2x0_.version as version4_0_0_ from Emp2 emp2x0_ where
emp2x0_.empno=? lock in share mode
T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]
T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=?
Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=?
T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
ERROR: Deadlock found when trying to get lock; try restarting transaction
T1 commit.
T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
T2 例外発生:javax.persistence.PersistenceException
T2 rollback.
T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]
79. PESSIMISTIC_FORCE_INCREMENTの実行ログ
Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 79
Hibernate: select emp2x0_.empno as empno1_0_0_, emp2x0_.ename as ename2_0_0_,
emp2x0_.sal as sal3_0_0_, emp2x0_.version as version4_0_0_ from Emp2 emp2x0_ where
emp2x0_.empno=? for update nowait
ERROR: ERROR: could not obtain lock on row in relation "emp2"
Hibernate: select emp2x0_.empno as empno1_0_0_, emp2x0_.ename as ename2_0_0_,
emp2x0_.sal as sal3_0_0_, emp2x0_.version as version4_0_0_ from Emp2 emp2x0_ where
emp2x0_.empno=? for update nowait
Hibernate: update Emp2 set version=? where empno=? and version=?
T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=2]
T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]
Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=? and version=?
T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]
T1 commit.
T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]
T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]