概要
ダイアログでOK押下された場合の削除処理を実行します。
画面からリクエストされた書籍情報IDをキーに、論理削除を実装します。
システム開発ではほとんどの場合、論理削除を行います。
物理削除するのは、洗い替えでデータを全て入れ替えるときくらいしか私は知りません。
フロントエンド
リクエスト
検索結果の削除ボタンからリクエストします。
その際、書籍情報IDとVersionが送信します。
1 2 3 4 5 6 7 |
<form th:action="@{/book/delete}" method="post"> <button class="delete-action" type="submit">削除</button> <input type="hidden" th:value="${book.id}" name="id"> <input type="hidden" th:value="${book.version}" name="version"> </form> |
・書籍情報ID
削除するキーになります。
・version
削除対象が他のユーザによって更新されていない場合のみ削除できるよう、
versionの値でチェックするために使用します。
楽観ロックのエラー表示
list.html(検索一覧)に、楽観ロックにより削除できなかった場合の
エラー表示枠を作成しておきます。
1 2 3 4 5 6 |
<div th:replace="book/search"></div> <div th:text="${error}"></div> <-- ここ <div th:if="${books}"> |
バックエンド
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// BookController.java @PostMapping("book/delete") public String postDelete(String id, String version, Model model) { try { service.delete(id, version); } catch (OptimisticLockingFailureException e) { model.addAttribute("error", e.getMessage().toString()); } return getList(model); } |
・serviceへの委譲
idとversionを引数に処理を委譲します。
他のユーザによって既に削除済か、更新されている場合は
削除できない旨のエラーメッセージが返却されます。
・エラーメッセージの返却
楽観ロックでエラーが発生した場合、画面上で表示できるように
エラーメッセージをmodelに格納しておきます。
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// BookService.java public void delete(String afterId, String afterVersion) throws OptimisticLockingFailureException { String userId = "kondo"; Book before = repository.selectOne(Integer.valueOf(afterId)); if(before != null && before.getVersion() == Integer.valueOf(afterVersion)) { repository.delete(afterId, afterVersion, userId); return; } throw new OptimisticLockingFailureException("削除データが無いか、すでに更新されています。"); } |
・楽観ロックによるチェック
更新処理時と同じで、楽観ロックによるチェックを行います。
もし既に削除済か更新されていた場合は、楽観ロックの例外(OptimisticLockingFailureException)が発生するようにしておきます。
・削除処理
削除済でも更新されてもいない場合は、削除処理を実行します。
Repositoryには、書籍情報ID、version、削除ユーザIDを引数に渡します。
Repository
BookRepostory.javaには、メソッドのみを実装します。
1 2 3 4 5 |
// BookRepostory.java public void delete(String id, String version, String deleted_user); |
SQLをXMLに記述します。
1 2 3 4 5 6 7 8 9 |
<!-- BookRepostory.xml --> <delete id="delete"> UPDATE book SET deleted_at = now(), deleted_user = #{deleted_user} WHERE id = #{id} AND version = #{version} </delete> |
・更新カラム
削除ユーザは引数の値とし、削除日時は実行日時とします。
・条件
引数で渡された、書籍情報IDとversionとします。
動作確認
- 削除処理が正常に実行されること
- 検索一覧で任意の書籍情報の削除ボタンを押下する。
- 削除ダイアログでOKボタンを押下する。
- 検索を実行し、削除した書籍情報が表示されていないこと。
- MySQL Workbenchでテーブルを参照し、削除したレコードの削除日時、削除ユーザが更新されていること。
- 削除処理がキャンセルされること
- 検索一覧で任意の書籍情報の削除ボタンを押下する。
- 削除ダイアログでキャンセルボタンを押下する。
- 検索を実行し、キャンセルした書籍情報が表示されていること。
- 楽観ロックによって削除が失敗すること
- 任意の条件で検索する。
- 検索結果の画面を複製する(Chrome想定[画面のタブを右クリック ⇒ タブを複製]
- 複製元画面の検索一覧から任意の書籍情報を編集する。
- 複製先画面の検索一覧から、複製元画面で編集した書籍情報と同じものを削除する。
- 削除処理に失敗した旨のエラーメッセージが検索画面に表示されること。
まとめ
- 削除処理は論理削除で実装する。
- 削除するキーはテーブルのユニークキー(今回の場合は書籍情報ID)である。
- versionは楽観ロックとして活用する。