處理 Mybatis 中一對多、多對一、多對多對映的黑魔法
前言
先看看Mybatis官方介紹
MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和對映原生資訊,將介面和 Java 的 POJOs(Plain Old Java Objects,普通的 Java物件)對映成資料庫中的記錄。
注意,這裡是簡單的XML! 可是,當我們的資料庫表關係錯綜複雜,表與表之存在一對多、多對一、多對多的關係時,如何通過mybatis表示出他們的關係呢?網上很多文章都在介紹 association、 collection,我先不說association、 collection有多好,先來看看一個具體例項。
下圖是訂單的資料庫表關係
有這樣一個需求,我要展示類似於淘寶訂單的效果,如下圖:
我們看到上面的訂單就會想到,要展示一條訂單,需要:訂單資訊、物流資訊、賣家資訊、買家資訊、商品資訊、商品屬性資訊、商品狀態資訊…,至少也要5/6張表的資料,其中,訂單對買家/賣家是多對一關係、訂單對商品時多對多關係…,看看類似的xml:
<span style="color:#000000"><code><span style="color:#880000"><!-- 查詢使用者及購買的商品 type寫的是user類的全路徑 把資料對映到user中 --></span> <span style="color:#006666"><<span style="color:#4f4f4f">resultMap</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"org.mybatis.po.User"</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"UserAndItemsResultMap"</span>></span> <span style="color:#880000"><!-- 使用者資訊 --></span> <span style="color:#006666"><<span style="color:#4f4f4f">id</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"user_id"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"id"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"username"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"username"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"sex"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"sex"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"address"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"address"</span> /></span> <span style="color:#880000"><!-- 訂單資訊一個使用者對應多個訂單,使用collection對映--></span> <span style="color:#006666"><<span style="color:#4f4f4f">collection</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"ordersList"</span> <span style="color:#4f4f4f">ofType</span>=<span style="color:#009900">"org.mybatis.po.Orders"</span>></span> <span style="color:#006666"><<span style="color:#4f4f4f">id</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"id"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"id"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"user_id"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"userId"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"number"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"number"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"createtime"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"createtime"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"note"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"note"</span> /></span> <span style="color:#880000"><!-- 訂單明細一個訂單包括 多個明細 --></span> <span style="color:#006666"><<span style="color:#4f4f4f">collection</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"orderdetailList"</span> <span style="color:#4f4f4f">ofType</span>=<span style="color:#009900">"org.mybatis.po.Orderdetail"</span>></span> <span style="color:#006666"><<span style="color:#4f4f4f">id</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"orderdetailid"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"id"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"orders_id"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"ordersId"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"items_id"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"itemsId"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"items_num"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"itemsNum"</span> /></span> <span style="color:#880000"><!-- 商品資訊一個訂單明細對應一個商品--></span> <span style="color:#006666"><<span style="color:#4f4f4f">association</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"items"</span> <span style="color:#4f4f4f">javaType</span>=<span style="color:#009900">"org.mybatis.po.Items"</span>></span> <span style="color:#006666"><<span style="color:#4f4f4f">id</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"items_id"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"id"</span>></span><span style="color:#006666"></<span style="color:#4f4f4f">id</span>></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"name"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"name"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"price"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"price"</span> /></span> <span style="color:#006666"><<span style="color:#4f4f4f">result</span> <span style="color:#4f4f4f">column</span>=<span style="color:#009900">"detail"</span> <span style="color:#4f4f4f">property</span>=<span style="color:#009900">"detail"</span> /></span> <span style="color:#006666"></<span style="color:#4f4f4f">association</span>></span> <span style="color:#006666"></<span style="color:#4f4f4f">collection</span>></span> <span style="color:#006666"></<span style="color:#4f4f4f">collection</span>></span> ... <span style="color:#880000"><!--還有賣家、買家、物流...--></span> ...</code></span>
僅僅這一個訂單,如果用association、 collection來實現,xml何其多、何其複雜!除了xml,還有一堆實體類要寫,寫著寫著很容易亂!這跟Mybatis官網上說的簡單xml相悖,我想要的效果是簡簡單單的像一個實體類就能對映的xml,任何人,無論是初學者還是老程式設計師都能一眼直觀的xml。
拋磚引玉
那麼,要怎樣將訂單的xml簡化,我先來一個拋磚引玉,mybatis和hibernate最大的區別是什麼?
Mybatis可以更細緻的定製化! hibernate 具體更強的移植性和快取機制。既然說Mybatis可以更細緻的定製化,如何定製!通過sql優化、sql定製,既然sql可以根據具體的需求而定,那麼我可以利用sql處理資料庫表的關係,只需要返回直觀的結果給我就行。一言蔽之,就是:把一對多、多對一、多對多關係扔到sql中去處理,xml只需要接收最直接、最簡單的資料即可!
<!-- 查詢使用者及購買的商品 type寫的是user類的全路徑 把資料對映到user中 --> <resultMap type="org.mybatis.po.User" id="UserAndItemsResultMap"> <!-- 使用者資訊 --> <id column="user_id" property="id" /> <result column="username" property="username" /> <result column="sex" property="sex" /> <result column="address" property="address" /> <!-- 訂單資訊一個使用者對應多個訂單,使用collection對映--> <collection property="ordersList" ofType="org.mybatis.po.Orders"> <id column="id" property="id" /> <result column="user_id" property="userId" /> <result column="number" property="number" /> <result column="createtime" property="createtime" /> <result column="note" property="note" /> <!-- 訂單明細一個訂單包括 多個明細 --> <collection property="orderdetailList" ofType="org.mybatis.po.Orderdetail"> <id column="orderdetailid" property="id" /> <result column="orders_id" property="ordersId" /> <result column="items_id" property="itemsId" /> <result column="items_num" property="itemsNum" /> <!-- 商品資訊一個訂單明細對應一個商品--> <association property="items" javaType="org.mybatis.po.Items"> <id column="items_id" property="id"></id> <result column="name" property="name" /> <result column="price" property="price" /> <result column="detail" property="detail" /> </association> </collection> </collection> ... <!--還有賣家、買家、物流...--> ...
好,回到訂單,顯示一個訂單需要哪些資訊,需要如下資訊:
<span style="color:#000000"><code><span style="color:#000088">public</span> <span style="color:#000088">class</span> OrderInfo {
<span style="color:#880000">//訂單id</span>
<span style="color:#000088">private</span> Integer id;
<span style="color:#880000">//訂單價格</span>
<span style="color:#000088">private</span> Integer price;
<span style="color:#880000">//訂單生成時間</span>
<span style="color:#000088">private</span> Date createdTime;
<span style="color:#880000">//訂單狀態</span>
<span style="color:#000088">private</span> Integer status;
<span style="color:#880000">//商品數量</span>
<span style="color:#000088">private</span> Integer util;
<span style="color:#880000">//買家電話</span>
<span style="color:#000088">private</span> String phone;
<span style="color:#880000">//買家名字</span>
<span style="color:#000088">private</span> String userName;
<span style="color:#880000">//物流地址</span>
<span style="color:#000088">private</span> String receiverAddress;
<span style="color:#880000">//支付方式</span>
<span style="color:#000088">private</span> String payName;
<span style="color:#880000">//商品名稱</span>
<span style="color:#000088">private</span> String productName;
<span style="color:#880000">//商品屬性</span>
<span style="color:#000088">private</span> String standard;
<span style="color:#880000">//賣家名稱</span>
<span style="color:#000088">private</span> String marketName;
<span style="color:#880000">//商品縮圖</span>
<span style="color:#000088">private</span> String productPhoto;
setter and getter...
</code></span>
- public class OrderInfo { //訂單id private Integer id; //訂單價格 private Integer price; //訂單生成時間 private Date createdTime; //訂單狀態 private Integer status; //商品數量 private Integer util; //買家電話 private String phone; //買家名字 private String userName; //物流地址 private String receiverAddress; //支付方式 private String payName; //商品名稱 private String productName; //商品屬性 private String standard; //賣家名稱 private String marketName; //商品縮圖 private String productPhoto; setter and getter...xml怎麼寫? 我不需要association、 collection就可以實現,把資料庫關係交給資料庫處理,我用最原始的and 表示(這裡以mysql為例)
<span style="color:#000000"><code>...
<select id=<span style="color:#009900">"selectOrderInfoByOrderId"</span> resultType=<span style="color:#009900">"com.vbtime.thor.wrapper.OrderInfo"</span> parameterType=<span style="color:#009900">"java.lang.Integer"</span>>
select o<span style="color:#009900">.id</span> as id, o<span style="color:#009900">.status</span> as status, o<span style="color:#009900">.price</span> as price,o<span style="color:#009900">.created</span>_time as createdTime, o<span style="color:#009900">.util</span> as util, u<span style="color:#009900">.name</span> as userName, u<span style="color:#009900">.phone</span> as phone, r<span style="color:#009900">.receiver</span>_address as receiverAddress, pay<span style="color:#009900">.name</span> as payName,
group_concat(concat(ps<span style="color:#009900">.name</span>,<span style="color:#009900">':'</span>,psv<span style="color:#009900">.value</span>) Separator <span style="color:#009900">';'</span>) as standard, m<span style="color:#009900">.name</span> as marketName,p<span style="color:#009900">.name</span> as productName,p<span style="color:#009900">.photo</span> as productPhoto
from rorder o, order_standard_value os, product_standard ps, product_standard_values psv, user u, product p, market m, order_market om, order_product op, pay_type pay, receiver r where
u<span style="color:#009900">.id</span> = o<span style="color:#009900">.user</span>_id <span style="color:#000088">and</span> p<span style="color:#009900">.id</span> = op<span style="color:#009900">.product</span>_id <span style="color:#000088">and</span> o<span style="color:#009900">.id</span> = op<span style="color:#009900">.order</span>_id <span style="color:#000088">and</span> m<span style="color:#009900">.id</span>= om<span style="color:#009900">.market</span>_id <span style="color:#000088">and</span> o<span style="color:#009900">.id</span> = om<span style="color:#009900">.order</span>_id <span style="color:#000088">and</span> o<span style="color:#009900">.id</span> = os<span style="color:#009900">.order</span>_id <span style="color:#000088">and</span> psv<span style="color:#009900">.id</span> = os<span style="color:#009900">.standard</span>_value_id <span style="color:#000088">and</span>
ps<span style="color:#009900">.id</span>= psv<span style="color:#009900">.product</span>_standard_id <span style="color:#000088">and</span> pay<span style="color:#009900">.id</span> = o<span style="color:#009900">.pay</span>_id <span style="color:#000088">and</span> r<span style="color:#009900">.id</span> = o<span style="color:#009900">.recevier</span>_id <span style="color:#000088">and</span> o<span style="color:#009900">.id</span> = <span style="color:#009900">#{orderId}</span>
</select>
...</code></span>