★楽観的ロック
レコード毎にバージョン番号を持ち、まず最初に対象となるデータを取得しておき、更新時にDB上の対象データのバージョン番号に変化が無いか調べ、変化があれば「自分より前に、自分以外の誰かが更新した=このまま登録しては他人の変更を上書きしてしまうのでダメ」、変化がなければ「誰にも更新されていない=そのまま更新してよい=その一瞬だけロックして書き込んですぐに開放する」と判断するというのが楽観的ロック。CVS、SVNなどのリビジョン番号での管理がこれに当たる。
この楽観的ロックに関する機能がJPAには備わっているというので、
エンティティでバージョン番号を意味する列に「 @Version」アノテーションを付加するだけ!
@Entity
@Table(name="sample_entity")
public class SampleEntity implements Serializable {
@Id
@Column(unique=true, nullable=false, length=100)
private String key;
@Column(nullable=false, length=100)
private String val;
@Version
@Column(nullable=false)
private long revision;
…
このようなエンティティクラスを使用して更新処理を行った場合、エラーの無い場合(新規登録時含む)はそのまま処理が進み、排他エラーになった場合はOptimisticLockExceptionが発生する。
★悲観的ロック
操作開始から終了までずっとロックしっぱなしにして、その間は他からの更新を許さないのが悲観的ロック。
ロックをかける方法は主に以下の二つ。
検索時にロック
任意のタイミングでロック
// 検索時にロックする場合・主キー検索
SampleEntity entity1 =
em.find(SampleEntity.class, "abc",
LockModeType.PESSIMISTIC_WRITE);
// 検索時にロックする場合・複数件検索
List<SampleEntity> entities =
em.createQuery("select s from SampleEntity s")
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getResultList();
// 任意のタイミングでロックする場合
SampleEntity entity2 = em.find(SampleEntity.class, "abc");
em.lock(entity2, LockModeType.PESSIMISTIC_WRITE);