jpaの同時実行制御とロック20140518 #ccc_r15 #jjug_ccc

Post on 16-Apr-2017

7.508 Views

Category:

Software

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 1

JJUG CCC 2014 Spring

Java EE 7対応!JPAの同時実行制御とロック

2014/05/18

(株)ウチダ人材開発センタ 多田真敏

このセッションについて

Twitterハッシュタグ : #ccc_r15

JPAの同時実行制御とロックについて、基礎から詳しく説明します

同時実行制御とロックにおいて、JPA実装とDBMSを変えたときの、挙動の違いや注意点を説明します

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 2

アジェンダ

まずは自己紹介

同時実行制御とロックとは?

JPAにおける同時実行制御とロック

今回のサンプルプログラム

EclipseLink×MySQLの場合

EclipseLink×PostgreSQLの場合

Hibernate×MySQLの場合

Hibernate×PostgreSQLの場合

まとめ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 3

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 4

まずは自己紹介

あんた、誰?

IT研修インストラクター、社会人7年目。三十路。

専門はJava、.NET、ネットワーク、業務知識など。

中小企業診断士、SJC-WC、応用情報技術者。

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 5

Twitter・ブログ

Twitter : @suke_masa

ブログ : Java EE 事始め!http://masatoshitada.hatenadiary.jp/

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 6

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 7

同時実行制御とロックとは?

ロックとは?

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 8

empno ename sal

101 Nishida 500000

102 Nohira 285000

103 Kiyama 245000

T1 T2

複数のトランザクションから同時に実行されたとき、データの不整合が起こらないように行・表・DBにロックをかける、DBMSの機能

○ ×

ロックなしの場合に起こる不整合

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)

READロックとWRITEロック

① READロック(共有ロック)他のトランザクションはREADロックは取得できるが、WRITEロックは取得できない

②WRITEロック(占有ロック、排他ロック)他のトランザクションはREADロックもWRITEロックも取得できない

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 10

先のトランザクション

READロック WRITEロック

後のトランザクション

READロック ○ ×

WRITEロック × ×

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 11

JPAにおける同時実行制御とロック

楽観的ロックと悲観的ロック

楽観的ロック(OPTIMISTIC)更新対象の行に対して、他のトランザクションからの更新は無いという前提に立つ

パフォーマンスは悲観的ロックと比較して高い

悲観的ロック(PESSIMISTIC)更新対象の行に対してロックをかけ、他のトランザクションからの更新をDBMSが防ぐ

パフォーマンスは楽観的ロックと比較して低い

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 12

楽観的ロック → DBMSのロック機能を利用しない悲観的ロック → DBMSのロック機能を利用する

バージョニング

「バージョン」を表す列を対象テーブルに追加

エンティティのバージョンフィールドには@Versionアノテーションを付加

バージョンの型はint(Integer)、short(Short)、long(Long)、java.sql.Timestampが使用可能

更新時にバージョンの値が更新(インクリメントなど)される

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 13

LockModeType

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 14

ロックモード 説明

OPTIMISTIC 楽観的ロック

OPTIMISTIC_FORCE_INCREMENT

楽観的ロック。バージョンの値をインクリメントする

PESSIMISTIC_READ 悲観的ロック。READロックを取得する

PESSIMISTIC_WRITE 悲観的ロック。WRITEロックを取得する

PESSIMISTIC_FORCE_INCREMENT

悲観的ロック。WRITEロックを取得し、バージョンの値をインクリメントする

NONE ロックしない(デフォルト)

※READ・WRITEは非推奨

LockModeTypeの指定方法

EntityManagerインターフェイス<T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode)void lock(Object entity, LockModeType lockMode)void refresh(Object entity, LockModeType lockMode)

Query(TypedQuery)インターフェイスQuery setLockMode(LockModeType lockMode)

NamedQueryアノテーションlockmode属性

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 15

金魚本では・・・

「4.5 同時実行」は6ページしかない

悲観的ロックについては0.5ページ程度

Java EE 5までは楽観的ロックしかなかった

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 16

参考資料

Java EE 7 Tutorial42. Controlling Concurrent Access to

Entity Data With Rocking

JSR-338 Java Persistence 2.13.4 Locking and Concurrency

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 17

SPECIAL THANKS!!

O社認定講師&データベーススペシャリストのY部長

外語大卒の後輩Kちゃん

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 18

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 19

今回のサンプルプログラム

実験環境

JPA実装EclipseLink 2.5.2-M1Hibernate Entity Manager 4.3.1.Final

DBMSPostgreSQL 8.4.19MySQL 5.6.16

その他Windows 7 SP1(x64)JDK 7u45Eclipse 4.3.1

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 20

2×2=4通り

使用するテーブル

empno(PK) ename sal version

101 Nishida 500000 1

102 Nohira 285000 1

103 Kiyama 245000 1

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 21

emp2

empno=101のレコードを検索後、そのレコードのsalを10000プラスする処理を、2スレッドから同時実行

バージョン列

エンティティクラス

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 22

@Entitypublic class Emp2 implements Serializable {

@Idprivate Integer empno; private String ename;private Integer sal;@Versionprivate Integer version;// setter/getter, equals(), hashCode(), toString()

}

version列と対応するフィールド

スレッドクラス

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 23

public class UpdateThread extends Thread {@Overridepublic void run() {

String threadName = Thread.currentThread().getName();EntityManagerFactory factory =

Persistence.createEntityManagerFactory("emp");EntityManager manager = factory.createEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();Emp2 emp = manager.find(Emp2.class, 101, LockModeType.NONE);int sal = emp.getSal();System.out.println(threadName + " 検索直後 " + emp);try {

Thread.sleep(1000);} catch (InterruptedException e) { e.printStackTrace(); }

ここでLockModeTypeを指定

スレッドクラス

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 24

try {emp.setSal(sal + 10000);System.out.println(threadName + " flush直前 " + emp);manager.flush();System.out.println(threadName + " flush直後 " + emp);tx.commit();System.out.println(threadName + " commit.");System.out.println(threadName + " commit直後 " + emp);

} catch (Exception e) {System.out.println(threadName

+ " 例外発生:" + e.getClass().getName());e.printStackTrace();tx.rollback();System.out.println(threadName + " rollback.");

}

スレッドクラス

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 25

System.out.println(threadName + " 終了 " + emp);manager.close();factory.close();

}}

メインクラス

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();

}}

マルチスレッドで同時実行

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 27

EclipseLink×MySQLの場合

NONE

ロックしない(デフォルト)

バージョニングは不要なので、@Versionをコメントアウト

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 28

@Entitypublic class Emp2 implements Serializable {・・・// @Version コメントアウトprivate Integer version;・・・

}

NONEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 29

[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]

T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 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 = ? WHERE (EMPNO = ?) bind => [510000, 101][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [510000, 101]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

実行の様子

① T1が検索→sal=500000

② T2が検索→sal=500000

③ T1がsal=500000+10000で更新

④ T2がsal=500000+10000で更新

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 30

salは最終的に510000になる

OPTIMISTIC

楽観的ロック

バージョニング必須

バージョンが無い場合はPersistenceException

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 31

@Entitypublic class Emp2 implements Serializable {・・・@Version // 必須private Integer version;・・・

}

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.OptimisticLockExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2](以下、スタックトレース)

実行の様子

① 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

実行後のバージョン値

ロールバックされたエンティティも、バージョン値がインクリメントされる

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.OptimisticLockExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]

バージョン値変更の検知方法

UPDATE文のWHERE句に主キーとバージョン列を指定している→バージョン値が既に変更されていた場合、更新行数はゼロになる

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 35

[EL Fine]: sql: UPDATE EMP2 SET SAL = ?, VERSION = ? WHERE ((EMPNO = ?) AND (VERSION = ?))

bind => [510000, 2, 101, 1]

OPTIMISTIC_FORCE_INCREMENT

楽観的ロック。バージョン値を強制的にインクリメントする

バージョニング必須

EclipseLinkの場合、挙動はOPTIMISTICと全く同じ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 36

OPTIMISTIC_FORCE_INCREMENTの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 37

[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]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, 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]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2][EL Fine]: sql: UPDATE EMP2 SET SAL = ?, VERSION = ? WHERE ((EMPNO = ?) AND (VERSION = ?)) bind => [510000, 2, 101, 1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T1 例外発生:javax.persistence.OptimisticLockExceptionT1 rollback.T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]

PESSIMISTIC_READ

悲観的ロック。READロックを取得→EclipseLinkではSELECT FOR UPDATE文が実行され、WRITEロックを取得する

バージョニング不要

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 38

@Entitypublic class Emp2 implements Serializable {・・・// @Version コメントアウトprivate Integer version;・・・

}

PESSIMISTIC_READの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 39

[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 = ? WHERE (EMPNO = ?) bind => [510000, 101]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [520000, 101]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]

実行の様子

① T1が検索、WRTIEロックを取得→sal=500000

② T2が検索しようとするが、T1がWRITEロックを取得しているので、DB内の待ち行列に入る

③ T1がsal=500000+10000で更新→コミットしたらロック解放

④ T2が待ち行列から出て検索、WRITEロックを取得→sal=510000

⑤ T2がsal=510000+10000で更新→コミットしたらロック解放

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 40

SQLログと実際の実行順序は違う

SQLログは、JPAがDBMSに発行した「つもり」のSQLが表示される

実際には、発行されてもDBMS内の待ち行列に入っている場合がある

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 41

[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 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]・・・

PESSIMISTIC_WRITE

悲観的ロック。WRITEロックを取得→EclipseLinkではPESSIMISTIC_READと挙動は同じ

バージョニング不要

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 42

PESSIMISTIC_WRITEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 43

[EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1][EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [510000, 101]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [520000, 101]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]

PESSIMISTIC_FORCE_INCREMENT

悲観的ロック。バージョン値を強制的にインクリメントする

チュートリアルにはWRITEロックかREADロックか記述されていない→JSRには「exclusive lock(=WRITEロック)」と書いてある

バージョニング必須

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 44

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]

実行の様子

① 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

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 47

EclipseLink×PostgreSQLの場合

EclipseLink×MySQLと挙動は同じ

以下、ログのみ記載

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 48

NONEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 49

[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]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [510000, 101][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [510000, 101]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

OPTIMISTICの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 50

[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]

T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 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.OptimisticLockExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2](以下、スタックトレース)

OPTIMISTIC_FORCE_INCREMENTの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 51

[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]

T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, 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][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.OptimisticLockExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]

PESSIMISTIC_READの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 52

[EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1][EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [510000, 101]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [520000, 101]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]

PESSIMISTIC_WRITEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 53

[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][EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [510000, 101]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=1][EL Fine]: sql: UPDATE EMP2 SET SAL = ? WHERE (EMPNO = ?) bind => [520000, 101]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]

PESSIMISTIC_FORCE_INCREMENTの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 54

[EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1][EL Fine]: sql: SELECT EMPNO, ENAME, SAL, VERSION FROM EMP2 WHERE (EMPNO = ?) FOR UPDATE bind => [101]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]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T1 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]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=3]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=3]T1 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=3]

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 55

Hibernate×MySQLの場合

NONE

発行されるSQLが微妙に異なるが、最終結果はEclipseLinkと同じ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 56

NONEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 57

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=?T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 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=?T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

OPTIMISTIC

ロールバックされたエンティティのバージョンはインクリメントされない

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 58

OPTIMISTICの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 59

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=?T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 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=?T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]Hibernate: select version from Emp2 where empno =?T2 例外発生:javax.persistence.OptimisticLockExceptionT1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

実行後のバージョン値

ロールバックされたエンティティは、バージョン値がインクリメントされない

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 60

T2 例外発生:javax.persistence.OptimisticLockExceptionT1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]T2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

謎のSELECT文

T1がcommit時に発行している→コミット前に、他のトランザクションからバージョンが変更されていないかどうかを確かめるためと思われる

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 61

T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]Hibernate: select version from Emp2 where empno =?T2 例外発生:javax.persistence.OptimisticLockException

OPTIMISTIC_FORCE_INCREMENT

flush時とcommit時の2回、バージョンがインクリメントされる

「謎のSELECT文」によるバージョン確認は無い

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 62

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.OptimisticLockExceptionT2 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]

実行後のバージョン値

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]

PESSIMISTIC_READ

SELECT・・・LOCK IN SHARE MODE文が実行され、READロックが取得される→T1とT2が互いにロック解放待ちとなり、デッドロック発生→片方はロールバックされ、もう片方のみがコミットされる

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 65

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 modeHibernate: 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 modeT2 検索直後 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 transactionT1 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.PersistenceExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

PESSIMISTIC_WRITE

SELECT FOR UPDATE文が実行され、WRITEロックが取得される→片方のトランザクションがコミット・ロック解放後、もう片方のトランザクションも実行される

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 67

PESSIMISTIC_WRITEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 68

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 updateHibernate: 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 updateT1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=?T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=?T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]

PESSIMISTIC_FORCE_INCREMENT

SELECT FOR UPDATE文が実行され、WRITEロックが取得される→片方のトランザクションがコミット・ロック解放後、もう片方のトランザクションも実行される

OPTIMISTIC_FORCE_INCREMENTと同様、flush時・commit時の2回、バージョンがインクリメントされる

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 69

PESSIMISTIC_FORCE_INCREMENTの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 70

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 updateHibernate: 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 updateHibernate: 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]Hibernate: update Emp2 set version=? where empno=? and version=?T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=4]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=4]Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=? and version=?T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=5]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=5]T2 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=5]

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 71

Hibernate×PostgreSQLの場合

Hibernate×PostgreSQL

PESSIMISTIC_FORCE_INCREMENTのみ、MySQLの場合と挙動が異なる

READロックはSELECT FOR SHARE文

上記以外は同じなので、ログのみ記載

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 72

NONEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 73

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=?T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 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]T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

OPTIMISTICの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 74

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]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 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=?T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]Hibernate: select version from Emp2 where empno =?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.OptimisticLockExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

OPTIMISTIC_FORCE_INCREMENTの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 75

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=?T1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 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=?T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=2]Hibernate: update Emp2 set version=? where empno=? and version=?T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=3]T2 例外発生:javax.persistence.OptimisticLockExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

PESSIMISTIC_READの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 76

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 shareHibernate: 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 shareT1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T2 検索直後 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: ERROR: deadlock detectedT2 例外発生:javax.persistence.PersistenceExceptionT2 rollback.T2 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]

PESSIMISTIC_WRITEの実行ログ

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 77

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 updateHibernate: 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 updateT1 検索直後 Emp2 [empno=101, ename=Nishida, sal=500000, version=1]T1 flush直前 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=?T1 flush直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 検索直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 commit.T1 commit直後 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T1 終了 Emp2 [empno=101, ename=Nishida, sal=510000, version=1]T2 flush直前 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]Hibernate: update Emp2 set ename=?, sal=?, version=? where empno=?T2 flush直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 commit.T2 commit直後 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]T2 終了 Emp2 [empno=101, ename=Nishida, sal=520000, version=1]

PESSIMISTIC_FORCE_INCREMENT

SELECT FOR UPDATE文にNOWAITオプションが付加される→後からのトランザクションは、待つことができないため例外発生

NOWAITオプションはMySQLには無い

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 78

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 nowaitERROR: 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 nowaitHibernate: 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]

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 80

まとめ

まとめ

ロックモード 相違点

OPTIMISTIC ・EclipseLinkでは、ロールバックされたエンティティのバージョン値もインクリメントされる

OPTIMISTIC_FORCE_INCREMENT

・Hibernateでは、flush時とcommit時の2回、バージョンがインクリメントされる

PESSIMISTIC_READ

・EclipseLinkでは、READロックではなくWRITEロックになる

PESSIMISTIC_FORCE_INCREMENT

・Hibernateでは、flush時とcommit時の2回、バージョンがインクリメントされる・Hibernate×PostgreSQLでは、SELECT FOR UPDATE文にNOWAITオプションが付加

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 81

開発時の注意

必ずSQLログを出力して、一通りの挙動を確認しておきましょう!

JPAのSQLログの順番は、実際にDB内で実行される順番とは異なる場合があるので、注意しましょう!

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 82

今回、入れられなかった内容

悲観的ロックのタイムアウト

javax.persistence.lock.timeout

悲観的ロックのスコープ

javax.persistence.lock.scope

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 83

技術の普及=教育の普及

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 84

教育の普及

技術の普及

Copyright UCHIDA HUMAN DEVELOPMENT all rights reserved. 85

top related