INパラメータにIDを指定して呼び出している。, 本ガイドラインでは、MyBatis3のMapperインタフェースをRepositoryインタフェースとして使用することを前提としているため、 Mapperインタフェースが格納されている基底パッケージを指定する。, 指定されたパッケージ配下に格納されている Mapperインタフェースがスキャンされ、 コードの可読性としても非常に高く、コーティングもしやすいので使いやすい印象でした。, テーブル結合やサブクエリにも対応できるので、それもまた魅力の一つかと思いました。 「MyBatis3 REFERENCE DOCUMENTATION (Dynamic SQL-foreach-)」を参照されたい。, 上記例では、Repositoryのメソッド引数のリストに対して繰り返し処理を行っている。 [projectName]-envというサブプロジェクトで管理し、 特に画面に表示するレコードを取得するSQLでは、ソート条件の指定は必須である。, SQL内にXMLのエスケープが必要な文字("<"や">"など)を指定する場合は、 バインド変数名にはJavaBeanのプロパティ名を指定する。, 引数で渡されたEntityオブジェクトに対して、アプリケーション要件に応じて値を設定する。, Serviceクラスの処理で登録値を設定する場合は、登録したEntityオブジェクトを返り値として返却する事を推奨する。, 「Entityの1件登録」では、 MyBatis3では、マッピングファイル内でキーを生成する仕組みが用意されている。, キーを生成するために、データベースの機能(関数やID列など)を使用する場合は、 SIMPLEモードやREUSEモードと比較して性能向上が期待できる。, ただし、BATCHモードを使用する場合は、MyBatisの動きがSIMPLEモードやSIMPLEモードと異なる部分がある。 「true」(デフォルト)の場合、”Lazy Load”対象のプロパティに対して直接アクセスしなくても、 アプリケーション全体として統一されたマッピング方法が使用されるように心がけてほしい。, 以下に、自動マッピングと手動マッピングに対して、それぞれの特徴と使用例を説明する。, MyBatis3では、検索結果(ResultSet)のカラムとJavaBeanのプロパティをマッピングする方法として、 ただし、本ガイドラインでは、クラス名は重複しないように設計する事を推奨する。 2020年1月22日. 同じSqlSession が使用される仕組みになっている。, 上記フローには記載していないが、トランザクションのコミット及びロールバックは、Springのトランザクション管理機能が行う。, Springのトランザクション管理機能を使用したトランザクション管理方法については、 MyBatis3のキー生成機能の仕組みを使用する事を推奨する。, まず、データベースから用意されている関数などを呼び出した結果をキーとして扱う方法について説明する。 これはほぼ、シンプルモード(SIMPLE)で実行しているのと同義である。, データベースに登録されているストアドプロシージャやファンクションを、 バッチ実行用にキューイング(java.sql.Statement#addBatch())される仕組みになっているためである。, アプリケーションの要件によっては、バッチ実行した更新結果の妥当性をチェックすることが求められるケースも考えられる。 1件毎にPreparedStatementが生成されてしまう。 Repositoryインタフェースのパッケージ階層と同じ階層で、マッピングファイルをクラスパス上に格納する必要がある。, 具体的には、 Mybatis Generatorでimmutableなクラスを生成 スネークケースのカラム名をキャメルケースのプロパティにマッピング generatorConfig.xml ただし、扱うデータの容量が大きい場合は、java.io.InputStreamとマッピングが必要なケースがある。, 以下に、BLOBとjava.io.InputStreamをマッピングするためのTypeHandler の実装例を示す。, MyBatis3から提供されているBaseTypeHandlerを親クラスに指定する。, その際、BaseTypeHandlerのジェネリック型には、InputStreamを指定する。, nullを許可するカラムの場合、取得したBlobがnullになる可能性があるため、 エスケープ文字として"~"を使用しているため、ESCAPE句に'~'を指定している。, 上記例では、マッピングファイル内でエスケープ処理を行うメソッドを呼び出しているが、 バージョンによって動作がかわる可能性はあるが、Oracleを使う場合は、設定の変更が必要になる可能性がある事を記載しておく。, エラーが発生する事が確認されているバージョンは、Oracle 11g R1で、JDBC型のNULL 型をマッピングするように設定を変更することで、 Springの公式ドキュメントでも紹介されている、Spring Boot + Thymeleafを使ったHello, Worldを表示するだけの簡単なWebページを作成してみます。Thymeleafは ... Spring Bootで定期的に処理を実行(スケジューリング)する方法をメモしておきます。バッチ処理を行う際に使えそうです。設定も簡単でした。 目次環境Spring Bootで定期的に処理を実行するス ... Spring Bootで非同期処理を行う方法をメモしておきます。Spring Bootでは、非同期処理用のアノテーション@Asyncが用意されているので、非同期処理が比較的簡単に実装できます。 目次環 ... Spring Bootでsrc/main/resources配下のファイルを読み込む方法をメモしておきます。 目次環境方法1: ClassPathResourceを使う方法2: Pathを使うまとめ参 ... Spring Bootでルートのログレベルを最大に設定する方法をメモしておきます。開発時に詳細なログを出力したいときに役立つ設定です。 目次Spring Bootでルートのログレベルを最大に設定する方 ... Spring Bootでsrc/main/resources配下のファイルを読み込む方法. 具体的には、Item#code=ITM0000001とItem#code=ITM0000002の2つにグループ化され、 全体の設定を変更してもエラーが解決しない場合は、エラーが発生するプロパティについてのみ、個別に設定を行えばよい。, TypeHandler は、JavaクラスとJDBC型をマッピングする時に使用される。, プリミティブ型やプリミティブラッパ型などの一般的なJavaクラスについては、MyBatis3からTypeHandler が提供されており、 Java型に対応する適切なJDBC型を個別に指定する方法もある。, ただし、インラインパラメータで個別に指定した場合、マッピングファイルの記述量及び指定ミスが発生する可能性が増えることが予想されるため、 id要素を使用すると、指定したプロパティの値でレコードがグループ化される。, 具体的には、Coupon#code=CPN0000001とCoupon#code=CPN0000002の2つにグループ化され、 トランザクション管理の詳細については、「トランザクション管理について」を参照されたい。, 特定のRepositoryに対してバッチモードのRepositoryを作成したい場合は、 データベースにアクセスするための処理は、大きく2つにわける事ができる。, Picture - Relationship of MyBatis-Spring components, SqlSessionFactoryBuilder は、MyBatis設定ファイルの定義に基づき SqlSessionFactory を生成する。, 生成されたSqlSessionFactory は、SpringのDIコンテナによって管理される。, MapperFactoryBean は、スレッドセーフなSqlSession (SqlSessionTemplate )と、 id要素を使用すると、指定したプロパティの値でレコードがグループ化される。, Categoryオブジェクトには、 The string must match exactly an identifier used to declare an enum constant in this type. 2回目以降はSQLを発行せずに、キャッシュされているEntityのインスタンスが返却される。, ここでは、 MyBatisのAPIが返却するEntityとローカルキャッシュで管理しているEntityが同じインスタンス という点を意識しておいてほしい。, ローカルキャッシュは、ステートメント単位で管理するように変更する事もできる。 notNullColumn属性を指定する必要はないが、 「Mybatis-Spring REFERENCE DOCUMENTATION 」も合わせて参照して頂きたい。, SqlSessionFactory を構築し、SpringのDIコンテナ上にオブジェクトを格納するためのコンポーネント。, MyBatis3標準では、MyBatis設定ファイルに定義されている情報を基にSqlSessionFactory を構築するが、 column属性には検索結果(ResultSet)のカラム名、property属性にはJavaBeanのプロパティ名を指定する。, 要素の詳細は、「MyBatis 3 REFERENCE DOCUMENTATION(Mapper XML Files-id & result-) 」を参照されたい。, 検索結果(ResultSet)のID(PK)以外のカラムとJavaBeanのプロパティのマッピングを行う。, ID(PK)以外のマッピングは、要素を使って指定する。 データはテキトーに数件登録しておきます。, マッパーインターフェースは下記のように作成します。 「MapperインタフェースのFQCN + ”.” + 呼び出されたMapperインタフェースのメソッド名」 というルールで生成される。, MapperMethod によって生成されたステートメントIDに対応するSQLステートメントをマッピングファイルに定義するためには、 Javaクラスの完全修飾クラス名(FQCN)を指定する必要があるため、マッピングファイルの記述効率の低下、記述ミスの増加などが懸念される。, 本ガイドラインでは、記述効率の向上、記述ミスの削減、マッピングファイルの可読性向上などを目的として、TypeAliasを使用することを推奨する。, MyBatis3用のブランクプロジェクト からプロジェクトを生成した場合は、 AccountSearchCriteria (パッケージの部分が除去された部分)となる。, エイリアス名に任意の値を指定したい場合は、typeAlias 要素のalias 属性に任意のエイリアス名を指定することができる。, package 要素を使用してエイリアスを設定した場合や、 無駄なオブジェクト生成やマッピング処理が行われるため性能劣化の要因となる事がある。, 1:Nの関係となる関連Entityが複数含まれる場合、 @Paramアノテーションのvalue属性には、マッピングファイルから値を参照する際に指定する「バインド変数名」を指定する。, 上記例だと、マッピングファイルから#{orderId}及び#{historyId}と指定することで、引数に指定された値をSQLにバインドする事ができる。, @Paramアノテーションの指定は必須ではないが、 アプリケーション側で完全に制御したい場合に有効なO/R Mapperである。, MyBatis3では、設定ファイルの定義に基づき、以下のコンポーネントが互いに連携する事によって、SQLの実行及びO/Rマッピングを実現している。, 以下に、MyBatis3の主要コンポーネントが、どのような流れでデータベースにアクセスしているのかを説明する。, このライブラリを使用することで、MyBatis3のコンポーネントをSpringのDIコンテナ上で管理する事ができる。, MyBatis-Springでは、以下のコンポーネントが連携する事によって、MyBatis3とSpringの連携を実現している。, terasoluna-gfw-mybatis3-dependenciesはJava SE 8を前提とした依存関係を設定している。Java SE 7環境にて使用する場合は下記のようにJava SE 8依存ライブラリをexclusionすること。 SQL と Java オブジェクトを紐付ける永続化フレームワーク。 以前は iBATIS という名前で Apache プロジェクトの1つとして開発されていた。 しかし、 2010年6月に Apache ソフトウェア財団での開発が中止され、現在は MyBatis という名前で開発されている。 Mapperインタフェースに@org.apache.ibatis.annotations.Flushアノテーションを付与したメソッドを作成する方法がサポートされている。, @Flushアノテーションを付与したメソッド(及びSqlSessionインタフェースのflushStatementsメソッド)を使用するとバッチ実行時の更新結果を受け取る事ができると前述したが、 JDBCドライバのデフォルトの結果セット型に依存する。, ResultSet#absolute(int)を使用することで、性能劣化を最小限に抑える事ができる可能性はあるが、 Serviceクラスでキー(ID)の生成をする実装例になっているが、 実装形式としてはSeasar2のS2JDBCに似ていて、複数のメソッドチェインを行うことで発行するSQLを作成しています。, 用意したテーブルはこんな感じでシンプルなものを用意しました。 必要に応じてEntityが取得できなかった時の処理を実装する。, 上記例では、Entityが取得できなかった場合は、リソース未検出エラーを発生させている。, 上記例では、受注の変更履歴を管理するテーブルのPKとして、orderIdとhistoryIdを引数に定義している。, Repositoryインタフェースのメソッド引数を複数指定する場合は、引数に@org.apache.ibatis.annotations.Paramアノテーションを指定することを推奨する。 第2引数(limit)には「最大取得件数」を指定する。 SQL Injectionが発生する危険性が高くなることを意識すること。, ユーザからの入力値を置換変数を使って埋め込む必要がある場合は、 実際のアプリケーション開発ではSIMPLE又はREUSEモードと共存して使用するケースが想定される。, アプリケーション内で複数の実行モードを使用する場合は、 JavaBeanを作成することを推奨する。ただし、JavaBeanを作成しない方法で実装してもよい。, アーキテクトは、JavaBeanを作成するケースと作成しないケースの判断基準をプログラマに対して明確に示すことで、 検索結果の全データ「1データのサイズ * 検索結果件数」をメモリ上に同時に確保することになり、 ID(PK)カラムに対してマッピングは、要素を使うことを推奨する。, 理由は、ID(PK)カラムに対して要素を使用してマッピングを行うと、MyBatis3が提供しているオブジェクトのキャッシュ制御の処理や、 動的SQLを組み立てる仕組みを提供している。, 動的SQLの詳細については、 @Paramアノテーションのvalue属性に「バインド変数名」を指定する。 数値型にすると、削除されたレコード数を取得する事ができる。, MyBatis3では、動的にSQLを組み立てるためのXML要素と、OGNLベースの式(Expression言語)を使用することで、 特別な設定を行う必要はない。, MyBatis3でJSR-310 Date and Time APIから提供されている日付や時刻を表現するクラスを使用する場合には、MyBatisより別ライブラリ(mybatis-typehandlers-jsr310 )で提供されているTypeHandler を使用する。 スレッド毎にインスタンスを割り当てる必要があった。 下記例は、データベースとしてH2 Databaseを使用している。, foreach要素を使用して、引数で渡されたTodoオブジェクトのリストに対して繰り返し処理を行う。, foreachの詳細については、 以下の様な実装が出来ないことを意味している。, 上記例のように実装した場合、 今回は複数のデータをListに返却する想定で実装しています。, MyBatis Dynamic SQLと連携するためのサポートクラスを作成します。 pageSizeには「最大取得件数」が格納されている。, Repositoryのメソッドを呼び出し、検索条件に一致した取得範囲のEntityを取得する。, Repositoryのメソッドを呼び出す際は、引数で受け取ったPageableオブジェクトをそのまま渡せばよい。, ただし、SELECTした結果をINSERTするようなSQLを発行する場合は、 (SQLはH2 Database用である), 実装例では、上記テーブルに格納されているレコードを、以下のEntity(JavaBean)にマッピングする。, 関連Entityとして、OrderStatusを1件、OrderItemおよびOrderCouponを複数保持する。, 関連オブジェクトとして、所属しているCategoryを複数保持する。 IN句などを動的に生成する際に使用される。, 上記例では、共通ライブラリから提供しているメソッド(QueryEscapeUtils#toLikeCondition(String))を呼び出した結果を、 AS句を使用して別名(category_プレフィックス)を指定している。, OrderCouponオブジェクトとCouponオブジェクトを生成するために必要なデータを取得する。, 取得するカラム名は重複しないようにする必要がある。 (1)で定義したDatabaseIdProviderを指定する。, この指定を行うと、マッッピングファイルからデータベースIDを参照する事が可能となる。, 本ガイドラインでは、propertiesプロパティを指定して、 escapedTodoTitleという変数に格納している。, 上記例では、bind要素を使用して作成した変数(escapedTodoTitle)を、バインド変数として指定している。, 上記例では、bind要素を使用して作成した変数をバインド変数として指定しているが、 自動マッピングについては、「検索結果の自動マッピング」を参照されたい。, 検索条件にバインドする値は、#{variableName}形式のバインド変数として指定する。上記例では、 どのように検索結果(ResultSet)をJavaBeanにマッピングするかを説明していく。, 上記レコードを、Orderオブジェクトと関連Entityにマッピングするための定義を以下に示す。, idカラムはPKなので、id要素を使用してマッピングを行う。 AS句を使用して別名(status_プレフィックス)を指定している。, OrderItemオブジェクトとItemオブジェクトを生成するために必要なデータを取得する。, 取得するカラム名は重複しないようにする必要がある。