天天看點

Mybatis實作進階映射一對一、一對多查詢

終于把論文寫得差不多了,系統也不急着完成,可以抽出點時間來完成這個系列的部落格了。在寫本部落格之前我是惶恐不安的,進階映射一貫是持久層架構裡的重中之重,小到自己開發小系統,大到企業級開發,表的存在從來就不獨立的。複雜交錯的表之間的聯系有時的确讓背景開發人員頭疼,而作為一個架構,要做的事就是把這種複雜程度降到最低。既然如此,我們就趕快進入正文吧。

先說一對一吧,前幾篇博文裡用到了User類,今天我們再加上一個Orders訂單類

Mybatis實作進階映射一對一、一對多查詢

一個訂單隻能由一個使用者建立,是以根據訂單查找使用者是一對一的查找,是以當我想查出訂單關聯使用者的所有記錄怎麼查呢?

我們知道這個查詢時不用輸入參數的,是以在select裡面是不用輸入parameterType的,由此可知查詢關鍵就在resultType了,的确,但是今天resultType有時會不夠用,當然這都是後話了,在一對一查詢裡面resultType完全是夠用的,是以先看看這個怎麼用吧

先分析一波,我們之前的所有的輸出都有相會映射成相應的類,而我們現在沒有一個既包含User屬性又包含Orders的類怎麼辦呢?

沒錯,就是建立一個滿足以上條件的類,在這裡有一個小技巧,我們大多時候不需要關聯表裡的所有屬性,比如在這裡我們隻要user類的使用者名和位址兩個屬性時,可以建立一個Orders類的擴充類,在該擴充類裡添加屬性username和address,就像下面

Mybatis實作進階映射一對一、一對多查詢

解決了映射類,接下來就是xml檔案了

先把sql語句貼上來

SELECT 
    orders.*, user.username, user.address
FROM
    orders,
    user
WHERE
    orders.user_id = user.id;      

這個sql語句很簡單我就不多說了,有了這個mapper.xml就簡單了

<select id="findOrderCustom" resultType="com.mybatis.pojo.OrderCustom">
    SELECT 
        orders.*, user.username, user.address
    FROM
        orders,
        user
    WHERE
        orders.user_id = user.id;
  </select>      

然後就是遵循規範把mapper接口中的方法寫了

//查詢Orders關聯User使用resultType
    public List<OrderCustom> findOrderCustom();      

最後是測試代碼

public class UserMapperTest {

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setUp() throws Exception {
        //得到配置檔案流
        InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //建立會話會話工廠
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    
    @Test
    public void testFindOrderCustom() throws Exception {
        //建立會話
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //建立mapper代理對象
        UserMapper userMapper= sqlSession.getMapper(UserMapper.class);
        List<OrderCustom> list=userMapper.findOrderCustom();
        //調用代理對象的方法,列印結果
        System.out.println(list.size());
        sqlSession.close();
    }
}      

大功告成,這個測試代碼我已經測試過了沒有問題,是以如果有跟初學者想拿着部落客的代碼運作一遍也是沒有問題的。

其實從最開始學到現在,部落客一直有一個疑問,為了實作映射一直以來表和類中屬性的命名都要保持一緻。但是我們的java類規範命名都是用駝峰命名法,而資料庫中屬性命名大多采用下劃線,這樣保持一緻不得不改變一方的命名規則,有沒有什麼方法可以兩全呢?

答案就是resultMap,跟resultType直接進行類的映射不同,resultMap講究的是屬性的映射。為了舉例我再引進一個類,商品類Goods

Mybatis實作進階映射一對一、一對多查詢

表結構是這樣的

Mybatis實作進階映射一對一、一對多查詢

接下來要做的事就是使用resultMap從表中查出所有的資料

 在使用resultMap之前要先定義它,怎麼定義呢,看代碼

<!-- 定義resultMap -->
    <resultMap type="com.mybatis.pojo.Goods" id="goodsResultMap">
        <id column="id" property="id"/>
        <result column="goods_name" property="goodsName"/>
        <result column="goods_price" property="goodsPrice"/>
    </resultMap>      

主鍵用的是id,普通屬性統一使用result。其中column和property分别代表在表和類中的屬性名。resultMap的id是為了讓下面的select語句引用的,接下來就給出select語句

<!-- 用resultMap查詢goods資訊 -->
    <select id="findGoodsResultMap" resultMap="goodsResultMap">
        select * from goods
    </select>      

整個xml的工作就算完成了,老規矩,下面給出mapper接口中的方法和測試代碼(注意所有的測試都要加上@before的内容,我這裡就懶得再寫了)

//查詢goods使用resultMap
    public List<Goods> findGoodsResultMap();      
//測試查詢goods使用resultMap
    @Test
    public void testFindGoodsResultMap() throws Exception {
        //建立會話
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //建立mapper代理對象
        UserMapper userMapper= sqlSession.getMapper(UserMapper.class);
        List<Goods> list=userMapper.findGoodsResultMap();
        //調用代理對象的方法,列印結果
        System.out.println(list.size());
        sqlSession.close();
    }      

寫到這裡,是不是有人想叫部落客用resultMap的方法來寫一寫之前一對一的查詢呢,放心吧,我後面也會講到的。

首先看需求,如果我想列出所有使用者的所有訂單,但是使用者資訊又不能重複該怎麼辦,這個時候resultType就不夠用了,因為需求是使用者資訊不能重複是以訂單類要以list的方式存在

使用者類中如下所示

Mybatis實作進階映射一對一、一對多查詢

而我們的user表能否直接與上面的類對應呢,顯然是不行的,既然不行的話resultMap就要上場了,之前就說過resultMap是細化到屬性的對應的,我們完全可以将User類中的list中的對象細化到單獨對應orders表,這樣問題就解決了啊,那resultMap要怎麼定義呢

首先把除去list的屬性映射完(懶得麻煩就隻寫了id,username,address三個屬性),寫完就是下面這個樣子

<resultMap type="com.mybatis.pojo.User" id="userAndOrdersResultMap">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="address" property="address"/>
 </resultMap>      

千萬要記住我們的主表是user表,是以這裡的type是User類

在resultMap裡有一個屬性collection,這個屬性是專門為list準備的,讓我們來看看加上這個會是什麼樣子的

<resultMap type="com.mybatis.pojo.User" id="userAndOrdersResultMap">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="address" property="address"/>
            <collection property="orderList" ofType="com.mybatis.pojo.Orders">
                <id column="id" property="id"/>
                <result column="user_id" property="user_id"/>
                <result column="number" property="number"/>
                <result column="createtime" property="createtime"/>
                <result column="note" property="note"/>
            </collection>
    </resultMap>      

在collection中的property對應類中的屬性名,ofType對應類中的list中的對象類型,在這裡就是Orders類了,剩下的東西就和之前的配置完全一樣了,無非是将orders類中的屬性名和表中的屬性名對應了。

接下來就是select語句了

<!-- 查詢使用者關聯訂單使用resultMap -->
    <select id="findUserAndOrdersResultMap" resultMap="userAndOrdersResultMap">
         SELECT 
            user.id, user.username, user.address, orders.*
        FROM
            orders,
            user
        WHERE
            user.id = orders.user_id;
    </select>      

是不是sql語句發現和之前寫的好像是一樣的,啊哈哈,我也是寫完才發現的,需求是随便編的。。。

下面是mapper接口中的方法和測試代碼(注意所有的測試都要加上@before的内容,我這裡就懶得再寫了)

//查詢User關聯Orders使用resultMap
    public List<User> findUserAndOrdersResultMap();      
//測試查詢User關聯Orders使用resultMap
    @Test
    public void testFindUserAndOrdersResultMap() throws Exception {
        //建立會話
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //建立mapper代理對象
        UserMapper userMapper= sqlSession.getMapper(UserMapper.class);
        List<User> list=userMapper.findUserAndOrdersResultMap();
        //調用代理對象的方法,列印結果
        System.out.println(list.size());
        sqlSession.close();
    }      
Mybatis實作進階映射一對一、一對多查詢

我的資料庫orders表中有三條記錄,兩條是同一個使用者建立的,是以輸出結果應該是2,沒問題

最後啰嗦一點

如果需求變成訂單再關聯商品資訊該怎麼寫呢,我們知道訂單和商品也是一對一的,即一個訂單裡面隻能有一個該商品的記錄(注意,這裡的一個指的不是一件,如果使用者買了多件該商品最後也會變成一個商品記錄,變的隻是數量而已),相當于在Orders類中增加一個Goods類作為屬性,這個時候該怎麼寫呢,Mybatis提供了一個叫做association的屬性用于關聯類,相當于在collection裡加上一個association,這個時候,xml檔案會變成這樣

<resultMap type="com.mybatis.pojo.User" id="userAndOrdersResultMap">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="address" property="address"/>
            <collection property="orderList" ofType="com.mybatis.pojo.Orders">
                <id column="id" property="id"/>
                <result column="user_id" property="user_id"/>
                <result column="number" property="number"/>
                <result column="createtime" property="createtime"/>
                <result column="note" property="note"/>


                <association property="goods" javaType="com.mybatis.pojo.Goods">
                    <id column="id" property="id"/>
                    <result column="goods_name" property="goodsName"/>
                    <result column="goods_price" property="goodsPrice"/>
                </association>


            </collection>
    </resultMap>      

這個部落客就不去測試了,反正套路都是一樣的

 有了association,之前那個訂單關聯使用者的查詢也就迎刃而解了,隻需在Orders類中加一個使用者類的屬性緊接着配一個association就OK了。

終于寫完了,我長舒了一口氣,花了大半個下午的時間呢,後面還會寫多對多查詢,整合spring架構的内容等等。。。

最後最後說一點,這些知識我也是在短期内學完的,算是現學現賣,如果哪位大神“随意”看了一眼發現了錯誤或者有更好的見解還請不吝賜教啊

轉載于:https://www.cnblogs.com/scuury/p/8575189.html