Doma2で楽観排他を実現する方法と更新失敗時の例外処理についてまとめる。
Domaの設定方法
エンティティクラスの楽観ロック用のバージョンカラムにあたるメンバ変数に@Version
を付与する。
@Entity @Table(name = "sample") @ToString @EqualsAndHashCode public class Sample { /** ID */ @Id @Column(name = "id") Integer id; ・ ・ /** バージョン */ @Version @Column(name = "version") Integer version; ・ ・ }
エンティティを自動生成する場合は、バージョン列の名前をversion
もしくはversion_no
とすることで、自動で@Version
アノテーションが付与される。
上記設定をしてデータを更新すると、以下のようなUPDATE文が実行される。
update sample set name = '佐藤', age = 27, description = '理系', version = 1 + 1 where id = 3 and version = 1
楽観ロック例外の処理(Spring Boot)
楽観ロック例外にはOptimisticLockingFailureException
がスローされるので、例外ハンドラで例外をキャッチして任意の処理を行う。
以下は楽観ロック例外を捕捉して、画面にエラーメッセージを表示する例である。
〇Service
import org.springframework.stereotype.Service; @Service @DBTransactional public class SampleServiceImpl implements SampleService { /** dao */ private SampleDao dao; /** * @param dao */ public SampleServiceImpl(SampleDao dao) { this.dao = dao; } @Override public void updateData(Sample sample) { sample.setDescription("りんごゼリーにはまる"); dao.update(sample); } @Override public Sample select() { Sample sample = dao.selectById(3); return sample; } }
〇Controller
package jp.co.cti.terashite.webapp.register.controller; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class HomeController { /** サービス */ private SampleService service; /** * @param service */ public HomeController(SampleService service) { this.service = service; } @RequestMapping(value = "/", method = RequestMethod.GET) public String index() { return "index"; } @RequestMapping(value = "/select", method = RequestMethod.POST) public String result(Model model) { Sample sample = service.select(); model.addAttribute("sample", sample); return "select"; } @RequestMapping(value = "/update", method = RequestMethod.POST) public String result2(@ModelAttribute Sample sample) { service.updateData(sample); return "result"; } @ExceptionHandler(OptimisticLockingFailureException.class) public String error(Model model) { model.addAttribute("message", "更新に失敗しました。検索からやり直してください"); return "index"; } }