MyBatisはAdvanced Associationクエリ関数を提供します。これにより、データベースによって取得された結果セットを定義されたJava Beansに簡単にマッピングできます。以下は、MyBatisが一般的な1対多で多面的な関係の複雑なマッピングをどのように扱っているかを示す例です。
ユーザーが複数のブログを開きたり、ブログに記事を投稿したり、コメントを許可したり、記事をタグ付けたりできるシンプルなブログシステムを設計します。ブログシステムは、主に次のテーブルで構成されています。
著者テーブル:著者情報表、著者の情報、ユーザー名とパスワード、メールアドレスなどを録音します。
ブログテーブル:ブログテーブル、著者は複数のブログを開くことができます。つまり、著者とブログの関係は1対多です。
投稿テーブル:記事の記録表、出版後の時間、タイトル、テキスト、その他の情報を記録します。ブログの下には多くの記事があり、ブログと投稿の関係は1対多です。
コメントテーブル:記事のコメントテーブル、記録記事のコメント、記事には多くのコメントがあります:投稿とコメントの対応は1対多です。
タグテーブル:記事のタグ分類を表すタグテーブル。記事には複数のタグを付けることができ、さまざまな記事にタグを適用できるため、タグと投稿の関係は多くの関係です。 (TAGとPOSTの多くの関係は、POST_TAGテーブルを介して反映されます)
post_tagテーブル:記事とタグの間の対応を記録します。
一般的に言えば、各テーブルの構造に基づいて対応するJavabean(またはPojo)を作成して、テーブルの基本的なCRUD操作を完了します。
上記の1つのテーブルの定義は、ビジネスニーズを満たすことができない場合があります。ビジネスでは、ブログオブジェクトには、以下の図に示すように、著者に関する情報と記事のリストが必要です。
このようなクラスのインスタンスを取得したい場合は、少なくともいくつかのステップが必要です。
1.ブログテーブルのブログIDを介してブログ情報をクエリし、クエリブログとタイトルをブログオブジェクトに割り当てます。
2。ブログ情報のクエリAuthoridによると、著者のテーブルに移動して、対応する著者情報を取得し、著者オブジェクトを取得し、ブログオブジェクトに割り当てます。
3。BlogIDによると、投稿テーブルの対応する投稿記事リストを照会し、<post>オブジェクトをブログオブジェクトに割り当てます。
このようにして、少なくとも3つのクエリステートメントが最下層で呼び出されます。次のコードをご覧ください。
/** blogidを介してbloginfoオブジェクトを取得*/ public static bloginfo arganicqueryontest(string blogid){bigdecimal id = new bigdecimal(blogid); sqlsession session = sqlsessionfactory.opensession(); bloginfo bloginfo = new bloginfo(); // 1。 BlogIDに従ってブログオブジェクトをクエリし、BlogInfoブログに値を設定します=(ブログ)SESSION.SELECTONE( "com.foo.bean.blogmapper.selectbyprimarykey"、id); bloginfo.setblogid(blog.getBlogid()); bloginfo.settitle(blog.getTitle()); // 2。ブログのAuthoridによると、データベースを入力して作成者情報を照会し、結果をbloginfo object Author著者=(著者)SESSION.SELECTONE( "com.foo.authormapper.selectbyprimarykey"、blog.getauthorid()); bloginfo.setauthor(著者); // 3。投稿オブジェクトをクエリして、bloginfoリスト投稿= session.selectlist( "com.foo.bean.postmapper.selectbyblogid"、blog.getblogid()); bloginfo.setposts(posts); // json文字列jsonobject object = new jsonobject(bloginfo)の形式でオブジェクトを印刷します。 system.out.println(object.toString()); bloginfoを返します。 }上記のコードから、bloginfoオブジェクトを取得する方が面倒であることがわかります。データベースクエリを合計3回呼び出し、必要な情報を取得してから、bloginfoオブジェクトを組み立てる必要があります。
ネストされたステートメントクエリ
MyBatisは、Nested Statementクエリと呼ばれるメカニズムを提供します。これにより、上記の操作を大幅に簡素化し、次のように構成とコードを追加できます。
<resultmap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id column = "blog_id" property = "blogid" /> <result column = "title" property = "title" /> <associationプロパティ= "column =" blog_author_id "javatype =" com.foo.bean.author " select = "com.foo.bean.authormapper.selectbyprimarykey"> </associate> <collectionプロパティ= "column =" blog_id "oftype =" com.foo.bean.post "select =" com.foo.bean.postmapper.selectbyblogid "> </collection resultmap = "bloginfo" parametertype = "java.math.bigdecimal"> select b.blog_id、b.title、b.author_id as blog_author_id from louluan.blog
/** blogInfoをblogidを介してbloginfoオブジェクトを取得*/ public static bloginfo nestedqueryontest(string blogid){bigdecimal id = new bigdecimal(blogid); sqlsession session = sqlsessionfactory.opensession(); bloginfo bloginfo = new bloginfo(); bloginfo =(bloginfo)session.selectone( "com.foo.bean.blogmapper.querybloginfobyid"、id); jsonObject object = new JSonObject(bloginfo); system.out.println(object.toString()); bloginfoを返します。 }前のクエリは、上記のコードを通じて完全に実現できます。ここでは、bloginfo =(bloginfo)session.selectone( "com.foo.bean.blogmapper.querybloginfobyid"、id)のみが必要です。コードでは、複雑なbloginfoオブジェクトを取得できます。
ネストされたステートメントクエリの原則
上記のコードでは、MyBatisが次のプロセスを実行します。
1.最初にQueryBloginFobyIDの対応するステートメントを実行して、ブログテーブルから結果の結果を取得します。
2。結果の次の有効なレコードを取り出し、結果マップで定義されたマッピング仕様に基づいて、対応するblogInfoオブジェクトを構築します。
3. bloginfoに著者属性を割り当てたい場合、関連するクエリがあることがわかります。この時点で、MyBatisは最初にSelect Queryステートメントを実行して返された結果を取得し、結果をBlogInfoの著者属性に設定します。
4. bloginfoの投稿を割り当てるとき、同様のプロセスも存在します。
5.結果が出るまで2つのステップを繰り返します。 next()== false;
以下は、bloginfoオブジェクトの構築割り当てプロセスの概略図です。
この種の関連付けられたネストされたクエリの非常に良い機能は、Selectステートメントを再利用し、単純な選択ステートメント間の組み合わせを通じて複雑なオブジェクトを構築できることです。 com.foo.bean.authormapper.selectbyprimarykeyおよびcom.foo.bean.postmapper.selectbyblogidの上にネストされた2つの選択されたステートメントは、独立して使用できます。
n+1の問題
その短所も非常に明白です。いわゆるN+1の問題です。関連するネストされたクエリには結果セットが表示され、関連するクエリはこの結果セットの各レコードに基づいて実行されます。
ここで、ネストされたクエリが1つしかないと仮定します(つまり、結果マップ内にアソシエーションタグがあります)、クエリによって返されるエントリの数はnであり、関連するクエリステートメントがn回実行され、Query自体は結果セットを1回返し、合計N+1回はデータベースにアクセスするために必要です。 Nが比較的大きい場合、このようなデータベースアクセス消費量は非常に大きいです!したがって、この種のネストされたステートメントクエリを使用するユーザーは、N値がそれほど大きくないことを確認するために慎重に検討する必要があります。
例として、selectステートメント自体は、com.foo.bean.blogmapper.querybloginfobyidを使用して結果セットを1で返します。2つの関連するステートメントクエリがあるため、データベース1*(1+1)= 3倍にアクセスする必要があります。
ネストされた結果クエリ
ネストされたステートメントを照会すると、不確実なデータベースアクセス時間を引き起こす可能性があり、パフォーマンスに影響を与える可能性があります。 MyBatisは、ネストされた結果のクエリの一種もサポートしています。つまり、1対多、多目的、および多くの状況のクエリのために、MyBatisは共同クエリを通じてデータベースの結果を一度に検索し、その後、1対1の、多数の関係と結果を必要としています。
Bloginfoの結果マップを再定義します
<resultmap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id column = "blog_id" property = "blogid"/> <result column = "title" property = "title"/> <associationプロパティ= "著者=" blog_author_id "javatype =" com.foo.bue.bue.bue.bue.bue.bue.bue.bue.bue.bue.bue.bue. column="user_name" property="userName"/> <result column="password" property="password"/> <result column="email" property="email"/> <result column="biography" property="biography"/> </association> <collection property="posts" column="blog_post_id" ofType="com.foo.bean.Post"> <id column="post_id" property="postId"/> <result column = "blog_id" property = "blogid"/> <result column = "create_time" property = "createTime"/> <result column = "subject" property = "subject"/> <result column = "body" property = "body"/> <result columm
対応するSQLステートメントは次のとおりです。
<選択id = "queryallbloginfo" resultmap = "bloginfo"> select b.blog_id、b.title、b.author_id as blog_author_id、a.author_id、a.user_name、a.password、a.email、a.biography、p.post_id、p.blog_id as bod_id、p.prog_id、p.create_idブログBから左の外側の結合著者b.author_id = a.author_id左外の左外結合p.blog_id = b.blog_id </select>
/**すべてのブログに関するすべての情報を取得*/ public static bloginfo nestedResultontest(){sqlsession session = sqlsessionfactory.opensession(); bloginfo bloginfo = new bloginfo(); bloginfo =(bloginfo)session.selectone( "com.foo.bean.blogmapper.queryallbloginfo"); jsonObject object = new JSonObject(bloginfo); system.out.println(object.toString()); bloginfoを返します。 }ネストされた結果クエリの実行手順:
1.結果セットを取得するために、テーブルの対応する関係に基づいて結合操作を実行します。
2。結果を設定した情報とbloginfoの結果マップ定義情報によると、bloginfoを構築するためにメモリに設定された返された結果を組み立てて割り当てます。
3.作成された結果リスト<BlogInfo>結果を返します。
関連する結果クエリの場合、それが多面的な関係の場合、<Association Property = "Author" column = "blog_author_id" javatype = "com.foo.bean.author">によって構成されます。 MyBatisは、列プロパティに対応する著者_ID値からメモリからデータを取得し、それをAuthorオブジェクトにカプセル化します。
ブログと投稿の関係と同様に、1対多数の関係である場合、<collectionプロパティ= "column" column = "blog_post_id" oftype = "oftype =" oftype = ">で構成されています。
関連する結果を照会するには、データベースを一度クエリするだけで、結果の統合とアセンブリがすべてメモリに配置されます。
上記は、すべてのブログ情報を照会して、1対1のマッピングオブジェクト処理を実証することです。
PS:自己関連マッピングの例:
エンティティクラス
パブリッククラスモジュール{private int id;プライベート文字列キー。プライベート文字列名;プライベートモジュールParentmodule;プライベートリスト<モジュール> ChildrenModules;プライベート文字列URL;プライベートINTソート;プライベートストリングショー。プライベートストリングデル; public int getid(){return id; } public void setid(int id){this.id = id; } public string getKey(){return key; } public void setKey(string key){this.key = key; } public string getname(){return name; } public void setName(string name){this.name = name; } public Module getParentModule(){return parentModule; } public void setParentModule(Module ParentModule){this.ParentModule = ParentModule; } public string geturl(){return url; } public void seturl(string url){this.url = url; } public int getSort(){return sort; } public void setSort(int sort){this.sort = sort; } public string getshow(){return show; } public void setshow(string show){this.show = show; } public string getDel(){return del; } public void setdel(string del){this.del = del; } public list <odule> getChildrenModules(){return childrenmodules; } public void setChildrenModules(list <odule> childrenmodules){this.childrenmodules = childrenmodules; }} XMLコード: <mapper namespace = "com.sagaware.caraccess.mapper.modulemapper"> <resultmap type = "module" id = "moduleResultmap"> <idプロパティ= "id" column = "module_id"/> <resportプロパティ= "key" column = "module_key"/> <result property = "colum" colum = "module_url"/> <resultプロパティ= "sort" column = "module_sort"/> <respursプロパティ= "show" column = "module_show"/> <resport property = "del" column = "module_del"/> <! - query the parent module--> <ocationsプロパティ= "parentmodule"サブモジュール - > <コレクションプロパティ= "childrenmodules" column = "module_id" select = "getChildrenModules"/> </resultmap> <select id = "getmodules" parametertype = "string" resultmap = "moduleResultmap"> select * select * select * parametertype = "int" resultmap = "moduleResultmap"> select * from tb_module where module_id = {module_id} </select> <select id = "getChildrenModues" parametertype = "int" resultmap = "moduleresultmap"> select * </mapper>