バッチ削除

DAO メソッドに @BatchDelete を付けて、バッチ削除操作を実行します。

@Dao
public interface EmployeeDao {
    @BatchDelete
    int[] delete(List<Employee> employees);
    // ...
}

デフォルトでは、DELETE ステートメントが自動生成されます。 @BatchDelete アノテーション内の sqlFile プロパティに true を設定することで、任意の SQL ファイルをマッピングできます。

エンティティ パラメータでエンティティリスナーが指定されている場合、エンティティリスナーの preDelete メソッドは、削除を実行する前に各エンティティごとに呼び出されます。また、エンティティリスナーメソッドの postDelete メソッドは、削除実行後に各エンティティごとに呼び出されます。

戻り値

パラメータ Iterable のサブタイプの要素が不変エンティティクラスの場合、戻り値はエンティティクラスを要素として持つ org.seasar.doma.jdbc.BatchResult でなければなりません。

上記の条件が満たされない場合、戻り値は各削除プロセスの更新回数を表す int[] でなければなりません。

自動生成SQLによるバッチ削除

パラメータの型は要素として エンティティ を持つ java.lang.Iterable のサブタイプでなければなりません。指定できるパラメータは 1 つだけです。パラメータは null であってはなりません。戻り値の配列要素数は、 Iterable 要素数と等しくなります。戻り値の配列のそれぞれの要素は削除された件数を表します。

自動生成された SQL におけるバージョン番号と楽観的排他制御

以下の条件を満たした場合、楽観的排他制御が実行されます。

  • パラメータ java.lang.Iterable サブタイプ内の エンティティ に @Version アノテーションが付けられたプロパティがある

  • @BatchDelete アノテーション内のignoreVersion要素がfalseである

楽観的排他制御が有効な場合、バージョン番号と識別子が削除条件に含まれます。削除件数が 0 の場合、楽観的排他制御の失敗を表す BatchOptimisticLockException がスローされます。

ignoreVersion

@BatchDelete アノテーション内の ignoreVersion プロパティが true の場合、バージョン番号は削除条件に含まれません。削除数が0であっても BatchOptimisticLockException はスローされません。

@BatchDelete(ignoreVersion = true)
int[] delete(List<Employee> employees);

suppressOptimisticLockException

@BatchDelete アノテーションの suppressOptimisticLockException プロパティが true に設定されている場合、削除条件にバージョン番号が含まれますが、削除件数がゼロでも BatchOptimisticLockException はスローされません。

@BatchDelete(suppressOptimisticLockException = true)
int[] delete(List<Employee> employees);

SQLファイルによるバッチ削除

SQLファイルによるバッチ削除を実行するには、 @BatchDelete アノテーション内の sqlFile プロパティに true を設定し、対応するSQLファイルを用意します。

@BatchDelete(sqlFile = true)
int[] delete(List<Employee> employees);

パラメータの型は、任意の型を要素として持つ java.lang.Iterable サブタイプでなければなりません。指定できるパラメータは 1 つだけです。パラメータは null であってはなりません。戻り値の配列要素数は、 Iterable 要素数と等しくなります。配列のそれぞれの要素が削除された件数を表します。

例えば、上記のメソッドに対応するには以下のようなSQLを記述します。

delete from employee where name = /* employees.name */'hoge'

SQL ファイル内では、メソッドのパラメータ名は java.lang.Iterable の要素を示します。

SQLファイルにおけるバージョン番号と楽観的排他制御

以下の条件を満たした場合、楽観的排他制御が実行されます。

  • パラメータの java.lang.Iterable のサブタイプには エンティティ 要素があり、 エンティティ 要素には @Version の注釈が付けられている

  • @BatchDelete アノテーション内のignoreVersion要素がfalseである

ただし、楽観的排他制御のためのSQLを記述するのはアプリケーション開発者の責任となります。たとえば、以下の SQL のように、WHERE 句にバージョン番号を指定する必要があります。

delete from EMPLOYEE where ID = /* employees.id */1 and VERSION = /* employees.version */1

この SQL で削除件数が 0 以上の場合、楽観的排他制御の失敗を表す BatchOptimisticLockException がスローされます。

ignoreVersion

@BatchDelete アノテーションの ignoreVersion プロパティが true に設定されている場合、削除件数が 0 または複数でも BatchOptimisticLockException はスローされません。

@BatchDelete(sqlFile = true, ignoreVersion = true)
int[] delete(List<Employee> employees);

suppressOptimisticLockException

@BatchDelete アノテーションの suppressOptimisticLockException プロパティが true に設定されている場合、削除された件数が 0 または複数であっても BatchOptimisticLockException はスローされません。

@BatchDelete(sqlFile = true, suppressOptimisticLockException = true)
int[] delete(List<Employee> employees);

クエリタイムアウト

@BatchDelete アノテーション内の queryTimeout プロパティにクエリタイムアウトの秒数を指定できます。

@BatchDelete(queryTimeout = 10)
int[] delete(List<Employee> employees);

この指定はSQLファイルの使用の有無に関わらず適用されます。 queryTimeout プロパティに値が設定されていない場合は、config クラスで指定されたクエリタイムアウトが使用されます。

バッチサイズ

バッチサイズは @BatchDelete アノテーション内の batchSize プロパティに指定できます。

@BatchDelete(batchSize = 10)
int[] delete(List<Employee> employees);

この指定は、SQL ファイルの使用の有無に関係なく適用されます。 batchSize プロパティに値を指定しない場合は、設定 クラスで指定されたバッチサイズが適用されます。

非常に大きなバッチでメモリ使用量を抑える

デフォルトでは、バッチに含まれるすべての PreparedSql がデータベースへの送信前にあらかじめ構築されます。数十万件規模の非常に大きなエンティティリストでは、batchSize を設定していてもヒープを使い切る可能性があります。batchSizeexecuteBatch() 1 回あたりに JDBC ドライバへ送る件数を決めるだけで、メモリ上に同時に存在する PreparedSql の数を制御するものではないからです。

ピーク時のメモリ使用量を抑えるには、ConfigQuery implementors をオーバーライドして ChunkedAutoBatchDeleteQuery をオプトインで利用できます:

public class MyConfig implements Config {
    private final QueryImplementors queryImplementors = new QueryImplementors() {
        @Override
        public <ENTITY> AutoBatchDeleteQuery<ENTITY> createAutoBatchDeleteQuery(
                Method method, EntityType<ENTITY> entityType) {
            return new ChunkedAutoBatchDeleteQuery<>(entityType);
        }
    };

    @Override
    public QueryImplementors getQueryImplementors() {
        return queryImplementors;
    }
    // ... other Config methods ...
}

このオーバーライドを適用すると、自動生成 SQL を使うすべての @BatchDelete Dao メソッドは、エンティティ 1 件分の準備済み SQL を順次構築し、バインド・JDBC バッチへの追加を行ったのち、次の SQL を構築する前に GC 対象になります。JDBC バッチのフラッシュ境界は引き続き batchSize に従いますが、メモリ上の SQL リスト自体は O(1) に保たれます。

これは完全なオプトインです。QueryImplementors を差し替えない限り、挙動は変わりません。

SQLログの出力形式

SQLログの出力形式は @BatchDelete アノテーション内の sqlLog プロパティに指定できます。

@BatchDelete(sqlLog = SqlLogType.RAW)
int[] delete(List<Employee> employees);

SqlLogType.RAW は、SQLステートメントとそのバインドパラメータをログに出力します。