Enter search terms or a module, class or function name. そのまま、現場で学んだ(使用した)ツール等についてまとめていくシリーズです。 自分のためでもあり、それが誰かのためになればいいな、という気持ちを込めて書きます。 間違えや記述方法についての指摘やコメント、お待ちしております! https://atsuizo.hatenadiary.jp/rss, atsuizoさんは、はてなブログを使っています。あなたもはてなブログをはじめてみませんか?, Powered by Hatena Blog 今回は、Oracle接続する処理をMyBatisにより実装してみたので、そのサンプルプログラムを共有する。MyBatisを利用すると、SQL文をそのまま利用することができるため、これまでのJPAと比べ、複数のテーブル結合を含む複雑なSQL文に対しても容易に対応できる。 fetchSize属性を省略した場合は、各JDBCドライバのデフォルト値が利用されるため、デフォルト値が全件取得するJDBCドライバの場合、メモリの枯渇の原因になる可能性があるので、注意が必要となる。, select要素を実装する前に、検索したレコードのカラムと、JavaBeanのプロパティのマッピング定義を行う。, resultMap属性を使わずに、resultClass属性で指定したJavaBeanのプロパティに、自動的にマッピングすることもできるが、取得レコードのカラム名と、JavaBeanのプロパティ名が一致している必要がある。 詳細は、Developer Guide(PDF)の「Dynamic Mapped Statements」(P.52)を参照されたい。, 個々の動的SQLをブロック化することで、ブロック全体として、prepend, open, close属性を制御することができる。, 検索結果が、0~N件となるクエリを発行し、条件に一致するデータをすべて取得する場合は、以下のような実装となる。, TERASOLUNA DAO標準機能のページネーション検索は、java.sql.ResultSet#nextを使って取得するレコードの開始位置までスキップする実装となっているため、 CLOBは文字列として扱うこともできるが、データの容量が大きくなると、メモリ枯渇の原因となる可能性がある。, CLOBを扱う場合は、jdbcType属性には"CLOB"を、typeHandler属性には"jp.terasoluna.fw.orm.ibatis.support.ClobReaderTypeHandler"を指定する。, FQCNで指定しているクラス名は、 typeAlias要素を使って別名を付与することで、シンプルに記載することができる。, SQLに渡されたパラメータオブジェクトが指定されているかを判定し、SQLを組み立てることができる。, SQLに渡されたパラメータオブジェクト(JavaBean)に指定したプロパティが存在するか判定し、SQLを組み立てることができる。, SQLに渡されたパラメータオブジェクト(JavaBean)のプロパティに値が指定されているか判定し、SQLを組み立てることができる。, SQLに渡されたパラメータオブジェクト(JavaBean)のプロパティに指定されている値を判定し、SQLを組み立てることができる。, compareProperty属性を使用することで、JavaBean内の別のプロパティの値と、比較することもできる。, SQLに渡されたバインド値が、コレクションや配列の場合、コレクションおよび配列の要素分処理を繰り返して、SQLを組み立てることができる。, 上記例は、JavaBeanの中のプロパティがコレクションの場合の実装例であるが、パラメータオブジェクト自体をコレクションにすることもできる。 先人はいるけれど、調べてみた。 比較演算子については、こちらにまとまってますね。 d.hatena.ne.jp 公式ドキュメントでは いきなり、ちょっとキツ目の表現でスタートします。 NULL 値の概念については、NULL が空の文字列 '' と同じであると考えがちな SQL の初心者が混乱することがよくあります。 自分のためでもあり、それが誰かのためになればいいな、という気持ちを込めて書きます。 select expr が NULL の場合、ISNULL() は 1 を返し、それ以外の場合は 0 を返します。 | 検索条件に一致するデータ件数が、非常に多い場合、処理性能に影響を与える可能性がある。 必要なときに、個別に取得する方法を採用した方がよいケースがある。 ]]>, ほとんどのArm IPが試し放題でスタートアップは年会費無料!?Arm Flexible Access, パラメタ.idがnullであり、パラメタ.nameがnullでない場合に発行されるSQL…, you can read useful information later efficiently. (更新時の更新件数、削除時の削除件数も同様である。), 一致方法(前方一致、後方一致、部分一致)の指定をJPQLとして指定する場合は、エスケープのみ行うメソッドを使用する。, 一致方法(前方一致、後方一致、部分一致)をロジック側で判定する場合は、エスケープされた値にワイルドカードを付与するメソッドを使用する。, ユーザからの入力値を置換変数を使って埋め込むと、SQL Injectionが発生する危険性が高くなることを意識すること。 でMybatisMapper.select()を実行することによりselectが実行され、その結果がTableEntityにマッピングされます。 BLOBはバイト配列として扱うこともできるが、データの容量が大きくなると、メモリ枯渇の原因となる可能性がある。, CLOBを扱うプロパティの型は、 原則java.io.Reader型で定義することを推奨する。 パラメータの状態により動的にSQLを発行したりできます! 物作りは楽しい. table_name fetchSize属性は、JDBCドライバとデータベース間の通信において、一度の通信で取得するデータの件数を設定するパラメータである。 なぜなら、使用しない関連オブジェクトを、同時に取得してしまった場合、性能劣化の原因となるケースがあるからである。, 使用頻度の低い、1:Nの関係をもつ関連オブジェクトについては、まとめて取得しない。 内部で別のSQLを実行する方法は、個々のSQLや、resultMap要素の定義が、非常にシンプルとなる。 3. [CDATA[ NULL - 安全等価。この演算子では、= 演算子のように等価比較が実行されますが、両方のオペランドが NULL であれば、NULL でなく 1 が返され、一方のオペランドが NULL の場合は、NULL でなく 0 が返されます。 性能要件を満たせる場合は、まとめて取得してもよいが、他の方法を検討した方がよい。, Mybatis設定ファイルのsetting要素のenhancementEnabled属性を、. いかに自分が使えているだけで理解していないかがよく分かりました。 expr1 が NULL でない場合、IFNULL() は expr1 を返し、それ以外の場合は expr2 を返します。IFNULL() は、使用されているコンテキストに応じて、数値または文字列値を返します。 間違えや記述方法についての指摘やコメント、お待ちしております!, XML、またはアノテーションを使用してSQL文とオブジェクトをマッピングするフレームワークです。, 通常のCRUD操作はもちろん、 パラメータオブジェクト(JavaBean)のプロパティの存在有無を判定, 5.3.2.4.3. MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.4 制御フロー関数, Nullと比較した場合、NullをInsertした1行だけをNullとしてを正しく検出しています。, ちょっと困りましたね。 Help us understand the problem. expr1 = expr2 が true の場合は NULL を返し、それ以外の場合は expr1 を返します。これは、CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END と同じです。 空文字をnullとして扱うという指定(with null as '')をすれば、回避できます。 COPY [テーブル名] FROM [ファイルの絶対パス] WITH NULL AS ''; こうして得た情報をもとに、いろいろ試してみたり、さらの別の単語で検索をすると解決できると思います。 両方のステートメントで phone カラムに値が挿入されていますが、最初のステートメントは NULL 値を挿入しており、2 番目のステートメントは空の文字列を挿入しています。最初のステートメントの意味は「電話番号がわからない」、2 番目のステートメントの意味は「この人は電話を持っていないため、電話番号がない」と見なすことができます。 ]]>で囲えば使用可能です!, ピンポイントで囲うよりもSQL全体を囲ってあげたほうが可読性は高いと思いますので、 パラメータオブジェクト(JavaBean)のプロパティ値の設定有無を判定, 5.3.2.4.4. ただし、半角スペースは、例によってトリミングされてしまうのです。, Feedly以外への登録は、お手数ですが以下URLを登録お願いします。 MySQL :: MySQL 5.6 リファレンスマニュアル :: B.5.5.3 NULL 値に関する問題, いつもどおり、環境はLinux上のMySQL 5.6.31です。 空文字とnullの扱い verticaでは、char型やvarchar型の列に「空文字」や「null」をinsertした場合、それぞれ結果が異なります。 以下に6パターンのデータの挙動を整理してみます。 , 最後までお読みいただき、ありがとうございました!, Javaエンジニア。 つまり、半角スペースは、何桁保存されていても、比較時にトリミングされてしまっているような挙動となります。, 念のため、半角スペースを検出できるか、半角スペースの桁数ごとの違いを認識できるか、チェックしておきます。, この仕様についての回避策については、「BINARY」句をつければいいって、先人の方が言っておりました。 この動作回避する方法として、Mybatisでは、関連オブジェクトを “Lazy Load” する方法を、オプションとして提供している。, 本節では、MyBatis2.xを使って、データベースにアクセスする方法について説明する。, 本ガイドラインでは、TERASOLUNA DAO(MybatisのラッパーDAO)を使用することを前提としている。, Mybatisは、O/R Mapperの一つだが、データベースで管理されているレコードと、オブジェクトをマッピングするという考え方ではなく、, SQLとオブジェクトをマッピングするという考え方で開発されたO/R Mapperである。, そのため、正規化されていないデータベースへアクセスする場合や、発行するSQLをO/R Mapperに任せずに、アプリケーション側で完全に制御したい場合に有効なO/R Mapperである。, ServiceまたはRepositoryから、TERASOLUNA DAOから提供されているDAOインタフェースのメソッドを呼び出す。, メソッドの呼び出しパラメータとして、SQLIDとSQLに埋め込む値を保持しているオブジェクトを渡す。, ServiceまたはRepositoryから指定されたSQLIDと、SQLに埋め込む値を保持しているオブジェクトもMybatisに渡される。, ローカルトランザクションを使用する場合、JDBCのAPIを呼び出してトランザクション制御を行う, アプリケーションサーバから提供されているトランザクションマネージャを使用する場合、JTAのAPIを呼び出してトランザクション制御を行う, Tomcat以外のAPサーバでは、nativeデータソースを取得できない場合があるので、, Springが提供している他のNativeJdbcExtractorを指定するか、各APサーバ用に、新たに, 詳細は、Mybatis Developer Guide(PDF)の「The SQL Map XML Configuration File」(P.8-16)を参照されたい。, プロパティファイルを読み込むための要素。読み込んだプロパティファイルに定義されているプロパティは、, 詳細は、Mybatis Developer Guide(PDF)の「The SQL Map XML Configuration File」(P.9)を参照されたい。, 設定項目の詳細については、Mybatis Developer Guide(PDF)の「The SQL Map XML Configuration File」(P.9-11)を参照されたい。, SQLマッピングファイルのselect要素、statement要素、procedure要素のresultClass属性、または、resultMap要素のclass属性に指定されたクラスのインスタンスを生成するファクトリクラスを指定する要素。, 詳細については、Mybatis Developer Guide(PDF)の「The SQL Map XML Configuration File」(P.11-12)を参照されたい。, ここで定義した別名は、Mybatisの設定ファイルおよびSQLマッピングファイルのクラスを指定する箇所で使うことができる。通常、パッケージを除いたシンプルなクラス名を指定することが多い。, 詳細については、Mybatis Developer Guide(PDF)の「The SQL Map XML Configuration File」(P.12)を参照されたい。, Parameter Maps and Inline Parameters(P.27-31), SQLにバインドするパラメータ(オブジェクト)のマッピングに関する、詳細な説明が記載されている。, SQLの実行結果として返却されるレコードと、オブジェクトのマッピングに関する、詳細な説明が記載されている。, Supported Types for Parameter Maps and Result Maps(P.42-43), ParameterMapと、ResultMapでサポートされている型と、拡張方法が記載されている。, Caching Mapped Statement Results(P.44-47), resultMapを使わずに、自動的にclass属性で指定したJavaBeanのプロパティにマッピングすることもできるが、取得レコードのカラム名と、JavaBeanのプロパティ名が一致している必要がある。, 取得レコードのカラム名とJavaBeanのプロパティ名を一致させる方法として、AS句を使って、カラム名に別名を付与する方法がある。, バインド用オブジェクトにJavaBeanを使用する場合は、バインド用の変数名は、JavaBeanのプロパティ名と一致させる必要がある。, 呼び出すProcedureやFunctionを、”{call Procedure/Function名(INパラメータ ...,OUTパラメータ...)}”の形式で指定する。, バインドされる値は、parameterMap要素で指定したマッピング定義の定義順となる。, BLOBおよびCLOBなどのLarge Objectを、データベースに更新する場合の実装例を、以下に示す。, BLOB型のカラムの登録値を保持するパラメータに対して、登録するために必要な定義を指定する。, 上記例では、ファイルIDをUUIDとして採番し、引数で受け取ったファイル名と、ファイルの中身が格納されている, BLOBおよびCLOBなどのLarge Objectを、データベースから取得する場合の実装例を、以下に示す。, BLOB型のカラムから取得した値を保持するプロパティに対して、値を取得するために必要な定義を指定する。, Mybatisでは、動的にSQLを組み立てる仕組みが、デフォルトで用意されている。, 詳細については、Developer Guide(PDF)の「Dynamic Mapped Statements」(P.48-53)を参照されたい。, 例では、パラメータオブジェクトが指定されている時に、idカラムをWHERE句に設定している。, 例では、パラメータオブジェクトが指定されていない時に、一致するレコードが0件になるように、条件「, コレクションまたは配列の要素が存在する場合に、最初に設定する文字列を指定する。例では、条件に加えるカラム名と、IN句を指定している。, コレクションまたは配列の最初の要素を処理する前に設定する文字列を指定する。例では、IN句に指定する値の開始囲い文字, 次の要素がある場合、次の要素の処理を行う前に設定する文字列を指定する。例では、IN句に指定する値の区切り文字, コレクションまたは配列の最後の要素の処理を行った後に、設定する文字列を指定する。例では、IN句に指定する値の終了囲い文字, ブロック内で組み立てたSQLの先頭に設定する文字列を指定する。ここで指定した値は、ブロック内で最初に一致した動的SQLのprepend属性の値として使用される。, 例では、booleanにしているが、複数のパラメータ(検索条件)を渡したい場合は、JavaBeanを指定することもできる。, 検索結果が、0~N件となるクエリを発行し、条件に一致するデータの一部(指定ページ部分)を取得する場合は、以下のような実装となる。, 以下の例では、TERASOLUNA DAOから提供されているAPIを使って、実現する実装例となっている。, 検索結果が0~N件となるクエリを発行し、条件に一致するデータの一部(指定ページ部分)を取得する場合は、以下のような実装となる。, 以下の例では、TERASOLUNA DAOから提供されているAPIを使わずに、SQLを使って実現する実装例となっている。, Pageableオブジェクトは、リクエストパラメータに指定して、Controllerの引数として受けることもできる。詳細は、, 0開始。取得件数が10件のときに、10を指定すると、11~20件目が取得される。(PostgreSQLの機能を使用する), 取得開始位置が、0のときに、10を指定すると、1~10件目が取得される。(PostgreSQLの機能を使用する), 複数のSQLを、バッチ実行することで、複数件のデータを挿入する場合は、以下のような実装となる。, 複数のSQLをバッチ実行することで、複数件のデータを更新する場合の実装例は、複数件挿入(バッチ実行)と同じである。, SQLで指定した条件に一致するデータを一括で更新する場合、以下のような実装となる。, 全レコードを同じ値に一括更新する場合は、WHERE句指定による複数件更新が有効的である。, 複数のSQLをバッチ実行することで、複数件のデータを削除する場合の実装例は、複数件更新(バッチ実行)と同じである。, 1件削除時の処理を共有する必要がある場合は、バッチ実行による複数件削除を使用する。ただし、削除する対象データが大量になる場合は、WHERE句指定による一括削除の方式を検討した方がよい。, SQLで指定した条件に一致するデータを一括で削除する場合の実装例は、複数件更新(WHERE句指定)と同じである。, 削除対象のレコードが大量になる場合は、WHERE句指定による複数件削除が有効的である。, プロシージャや、ファンクションのOUTパラメータが、バインド用オブジェクトに設定される。, 例では、バインド用オブジェクトに設定されたOUTパラメータの値を、ログに出力している。, 例では、無名クラスを使用しているが、実際のプロジェクトでは、実装クラスを作成することを検討すること。, 引数にわたってくるオブジェクトは、select要素にresultClass属性、または、resultMap要素のclass属性に指定したクラスのオブジェクトとなる。, LIKE検索を行う場合は、検索条件として使用する値を、LIKE検索用にエスケープする必要がある。, 以下に、共通ライブラリから提供しているエスケープ処理の、使用方法について説明する。, ロジック側で一致方法を指定する場合は、 以下の何れかのメソッドを呼び出し、LIKE検索用のエスケープとLIKE検索用のワイルドカードを付与する。, SQLを組み立てる際は、SQL Injectionが発生しないように、注意する必要がある。, この方法を使用すると、SQLを組み立てるタイミングで、文字列として置換されてしまうため、安全な値の埋め込みは、保証されない。, バインド変数を使用する場合は、 ParameterMapまたはInline Parametersを使用する。, バインド変数として値を埋め込むプロパティを定義する。定義した順番が、(2)で指定している, テーブル毎にEntityのようなJavaBeanを用意して、データベースにアクセスする際に、関連オブジェクトを、1回のSQLでまとめて取得する方法について説明する。, 関連するオブジェクトを、1回のSQLでまとめて取得する場合、取得したいテーブルをJOINして、マッピングに必要なすべてのレコードを取得する。, 取得したレコードは、resultMap要素にマッピング定義を行い、JavaBeanにマッピングする。, 以下では、1件のOrderを取得するSQL(findOne)と、すべてのOrderを取得するSQL(findAll)の実装例となっている。, 注文レコードとしては2件だが、レコードが複数件格納される関連テーブルと結合しているため、合計で9レコードが取得される。, 取得したレコードは、注文毎にグループ化する必要があるため、注文を一意に識別するための値が格納されている, 注文商品は、t_order_itemのプライマリキー(order_id,item_code)でグループ化する必要があるが、order_idカラムについては、親のresultMapで指定されているため、ここでは、item_codeカラムの値を保持する, カテゴリは商品毎にグループ化する必要があるため、商品を一意に識別するための値が格納されている, 本例では、1:Nの関係のテーブル(t_orderとt_order_line、t_orderとt_order_coupon)を複数結合しているため、 t_order_couponに複数レコードが格納されていると, 注文クーポンは、t_order_couponのプライマリキー(order_id,coupon_code)でグループ化する必要があるが、order_idカラムについては親のresultMapで指定されているため、ここでは、coupon_codeカラムの値を保持する, グレーアウトしている部分は、groupBy属性に指定によって、グレーアウトされていない部分にマージされる。, © Copyright 2013, NTT DATA.