検索

SELECTステートメントを使用して検索操作を実行するには、DAOメソッドに @Select を注釈として付けます。

@Dao
public interface EmployeeDao {
    @Select
    List<Employee> selectByDepartmentName(String departmentName);
    // ...
}

@Select アノテーションには SQLテンプレート が必要です。SQLファイルまたは @Sql アノテーションでSQLテンプレートを記述してください。

検索条件

検索条件はメソッドパラメータを使用して定義されます。以下のパラメータタイプがサポートされています。

パラメータータイプが基本タイプまたはドメインタイプである場合、引数として null を渡すことができます。それ以外のパラメータータイプでは、引数として null を渡すことはできません。

基本クラスまたはドメインクラスを使用したクエリ

メソッドのパラメータとして 基本クラス または ドメインクラス を宣言します。

@Select
List<Employee> selectByNameAndSalary(String name, Salary salary);

メソッドのパラメータをSQLにバインドするには、 バインド変数ディレクティブ を使用します。

select * from employee where employee_name = /* name */'hoge' and salary > /* salary */100

任意の型を使用したクエリ

メソッドのパラメータに任意の型を使用する場合は、バインド変数ディレクティブの中で . を使ってフィールドアクセスまたはメソッド呼び出しを行い結果をSQLにバインドします。

@Select
List<Employee> selectByExample(Employee employee);
select * from employee where employee_name = /* employee.name */'hoge' and salary > /* employee.getSalary() */100

複数のパラメータを指定できます。

@Select
List<Employee> selectByEmployeeAndDepartment(Employee employee, Department department);

IN句へのマッピング

IN句にバインドするには、パラメータとして java.lang.Iterable のサブタイプを使用します。

@Select
List<Employee> selectByNames(List<String> names);
select * from employee where employee_name in /* names */('aaa','bbb','ccc')

アグリゲート戦略

@SelectaggregateStrategy 要素は、事前に定義されたアグリゲート戦略に基づいて、クエリ結果を階層構造のエンティティにマッピングすることを可能にします。

@Select(aggregateStrategy = EmployeeStrategy.class)
Employee selectByName(String name);

詳細は、 アグリゲート戦略 を参照してください。

注釈

アグリゲート戦略は、 ストリーム検索 または コレクター検索 と組み合わせて使用することはできません。

検索オプション

SelectOptions を使用することで、SELECTステートメントをページングや悲観的排他制御のためのSQLへ変換することが可能です。

SelectOptions はDAOメソッドのパラメータとして定義されます。

@Dao
public interface EmployeeDao {
    @Select
    List<Employee> selectByDepartmentName(String departmentName, SelectOptions options);
    // ...
}

静的な get メソッドを使用して SelectOptions のインスタンスを取得できます。

SelectOptions options = SelectOptions.get();

ページング

ページネーションを実装するには、SelectOptions で取得するレコード数を指定するための limit メソッドと、開始位置を指定するための offset メソッドを使用します。この SelectOptions インスタンスを DAO メソッドに渡します。

SelectOptions options = SelectOptions.get().offset(5).limit(10);
EmployeeDao dao = new EmployeeDaoImpl();
List<Employee> list = dao.selectByDepartmentName("ACCOUNT", options);

ページングは、ファイルに記述されているオリジナルのSQLを書き換え実行することで実現されています。 オリジナルのSQLは次の条件を満たしていなければいけません。

  • SELECT ステートメントである

  • 最上位のレベルでUNION、EXCEPT、INTERSECT等の集合演算を行っていない (サブクエリで利用している場合は可)

  • ページング処理を含んでいない

さらに、ダイアレクト に従って特定の条件を満たす必要があります。

ダイアレクト

条件

Db2Dialect

offset を指定する場合は、ORDER BY 句で指定されたすべての列が SELECT 句に含まれる

Mssql2008Dialect

offset を指定する場合は、ORDER BY 句で指定されたすべての列が SELECT 句に含まれる

MssqlDialect

offset を指定する場合は、ORDER BY 句が存在する

StandardDialect

ORDER BY 句があり、ORDER BY 句で指定されたすべての列が SELECT 句に含まれる

悲観的排他制御

SelectOptionsforUpdate メソッドを使用すると、悲観的排他制御を指定できます。

SelectOptions options = SelectOptions.get().forUpdate();
EmployeeDao dao = new EmployeeDaoImpl();
List<Employee> list = dao.selectByDepartmentName("ACCOUNT", options);

SelectOptions は、 forUpdate で始まる名前を持つ悲観的排他制御のためのメソッドを提供します。 ロックされるテーブルや列のエイリアスを指定する forUpdate や ロックの取得を待機しない forUpdateNowait など。

Pessimistic concurrency control は、元の SQL を書き換えることによって達成されます。これは、以下の条件を満たす必要があります。

  • SELECT ステートメントである

  • 最上位のレベルでUNION、EXCEPT、INTERSECT等の集合演算を行っていない (サブクエリで利用している場合は可)

  • 楽観的排他制御の処理を含んでいない

ダイアレクトによっては、悲観的排他制御の一部またはすべての方法が使用できない場合があります。

ダイアレクト

説明

Db2Dialect

forUpdate()を使用できる

H2Dialect

forUpdate()を使用できる

HsqldbDialect

forUpdate()を使用できる

Mssql2008Dialect

forUpdate()とforUpdateNoWait()を使用できる。 ただし、オリジナルのSQLのFROM句は1つのテーブルだけから成らねばならない。

MysqlDialect

forUpdate() を使用できる

MysqlDialect (V8)

forUpdate(), forUpdate(String... aliases), forUpdateNowait(), forUpdateNowait(String... aliases) を使用できる

OracleDialect

forUpdate()、forUpdate(String... aliases)、forUpdateNowait()、forUpdateNowait(String... aliases)、forUpdateWait(int waitSeconds)、forUpdateWait(int waitSeconds, String... aliases) を使用できる

PostgresDialect

forUpdate() および forUpdate(String... エイリアス) を使用できる

StandardDialect

悲観的排他制御用のメソッドすべてを使用できない

カウント

SelectOptionsの count メソッドを使用して、レコードの総数を取得します。これは通常、ページネーションと共に使用され、ページネーションのフィルタリングが適用される前の総レコード数を取得します。

SelectOptions options = SelectOptions.get().offset(5).limit(10).count();
EmployeeDao dao = new EmployeeDaoImpl();
List<Employee> list = dao.selectByDepartmentName("ACCOUNT", options);
long count = options.getCount();

レコードの総数は、DAOメソッドを呼び出した後に SelectOptionsgetCount メソッドを使用して取得されます。 count メソッドがDAO メソッドの呼び出しより前に実行されていない場合、getCount メソッドは -1 を返します。

検索結果の保証

検索結果が少なくとも1つ返されるようにするには、 @Select アノテーションの ensureResult プロパティを true に設定します。

@Select(ensureResult = true)
Employee selectById(Integer id);

検索結果がない場合は、NoResultException がスローされます。

検索結果のマッピングの保証

結果セットのすべての列が欠落せずにエンティティのプロパティにマップされていることを確認したい場合、 @SelectensureResultMapping 要素に true を指定します。

@Select(ensureResultMapping = true)
Employee selectById(Integer id);

結果セットのカラムにマッピングされていないプロパティがある場合、 ResultMappingException がスローされます。

クエリタイムアウト

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

@Select(queryTimeout = 10)
List<Employee> selectAll();

queryTimeout プロパティの値が設定されていない場合は、 設定 で指定されたクエリタイムアウトが使用されます。

フェッチサイズ

@Select アノテーションの fetchSize プロパティで、フェッチサイズを指定できます。

@Select(fetchSize = 20)
List<Employee> selectAll();

fetchSize プロパティの値が設定されていない場合、 設定 で指定されたフェッチサイズが使用されます。

最大行数

@Select アノテーションの maxRows プロパティで、最大行数を指定できます。

@Select(maxRows = 100)
List<Employee> selectAll();

maxRows プロパティの値が設定されていない場合、 設定 で指定された最大行数が使用されます。

マップのキーの命名規則

検索結果を java.util.Map<String, Object> にマッピングする場合、 @SelectmapKeyNaming プロパティでマップのキーの命名規則を指定できます。

@Select(mapKeyNaming = MapKeyNamingType.CAMEL_CASE)
List<Map<String, Object>> selectAll();

MapKeyNamingType.CAMEL_CASE は、カラム名がキャメルケースに変換されることを示します。カラム名を大文字または小文字に変換する規約もあります。

最終的な変換結果は、ここで指定された値と 設定 で指定された MapKeyNaming の実装によって決定されます。

SQLログの出力形式

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

@Select(sqlLog = SqlLogType.RAW)
List<Employee> selectById(Integer id);

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