検索

SELECTステートメントを使用して検索を実行するには、DAOメソッドに @Select アノテーションを付けます。

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

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

注釈

検索結果に応じて エンティティクラスを作成する必要があります。たとえば、EMPLOYEE テーブルに対応する Employee クラスが宣言されている場合、EMPLOYEE テーブルの列を含む結果セットは Employee クラスとして受け入れられます。ただし、EMPLOYEEテーブルとDEPARTMENTテーブルを結合して得られる結果セットには、Employeeエンティティクラスとは別のクラス (例えばEmployeeDepartmentクラス) が必要です。

検索条件

検索条件にはメソッドのパラメータを使用します。使用可能なパラメータの型は次のとおりです。

パラメータの型が 基本クラス または ドメインクラス のいずれかである場合、引数を 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')

検索オプション

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

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

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

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

SelectOptions options = SelectOptions.get();

ページング

ページングを実行するには、 SelectOptionsoffset メソッドで開始位置、 limit メソッドで取得件数を指定し、 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

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

カウント

SelectOptionscount メソッドを呼び出すことで集計件数を取得できるようになります。 通常、ページングのオプションと組み合わせて使用し、ページングで絞り込まない場合の全件数を取得する場合に使います。

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 つあることを保証したい場合は、@SelectensureResult 要素に 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 アノテーションの maxRwos プロパティで、最大行数を指定できます。

@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をログに記録することを示します。