1. 程式人生 > >處理 Mybatis 中一對多、多對一、多對多對映的黑魔法

處理 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>