Mybatis----(2)

主要內(nèi)容

1 高級(jí)映射
一對(duì)一
一對(duì)多
多對(duì)多

1 高級(jí)映射

2-1 訂單商品數(shù)據(jù)模型

image.png
User表
Order表
Orderdetail表
item表

數(shù)據(jù)模型分析思路:即拿到一個(gè)項(xiàng)目的數(shù)據(jù)庫的分析方法

1、每張表記錄的數(shù)據(jù)內(nèi)容
分模塊對(duì)每張表記錄的內(nèi)容進(jìn)行熟悉,相當(dāng)于你學(xué)習(xí)系統(tǒng)需求(功能)的過程。
2、每張表重要的字段設(shè)置
非空字段、外鍵字段
3、數(shù)據(jù)庫級(jí)別表與表之間的關(guān)系
外鍵關(guān)系
4、表與表之間的業(yè)務(wù)關(guān)系
在分析表與表之間的業(yè)務(wù)關(guān)系時(shí)一定要建立 在某個(gè)業(yè)務(wù)意義基礎(chǔ)上去分析。

2-2 數(shù)據(jù)模型分析

image.png

用戶表user:
記錄了購買商品的用戶信息

訂單表:orders
記錄了用戶所創(chuàng)建的訂單(購買商品的訂單)

訂單明細(xì)表:orderdetail:
記錄了訂單的詳細(xì)信息即購買商品的信息

商品表:items
記錄了商品信息

表與表之間的業(yè)務(wù)關(guān)系:
在分析表與表之間的業(yè)務(wù)關(guān)系時(shí)需要建立 在某個(gè)業(yè)務(wù)意義基礎(chǔ)上去分析。
先分析數(shù)據(jù)級(jí)別之間有關(guān)系的表之間的業(yè)務(wù)關(guān)系:

usre和orders:
user---->orders:一個(gè)用戶可以創(chuàng)建多個(gè)訂單,一對(duì)多
orders--->user:一個(gè)訂單只由一個(gè)用戶創(chuàng)建,一對(duì)一

orders和orderdetail:
orders---》orderdetail:一個(gè)訂單可以包括 多個(gè)訂單明細(xì),因?yàn)橐粋€(gè)訂單可以購買多個(gè)商品,每個(gè)商品的購買信息在orderdetail記錄,一對(duì)多關(guān)系

orderdetail--> orders:一個(gè)訂單明細(xì)只能包括在一個(gè)訂單中,一對(duì)一

orderdetail和itesm:
orderdetail---》itesms:一個(gè)訂單明細(xì)只對(duì)應(yīng)一個(gè)商品信息,一對(duì)一

items--> orderdetail:一個(gè)商品可以包括在多個(gè)訂單明細(xì) ,一對(duì)多

再分析數(shù)據(jù)庫級(jí)別沒有關(guān)系的表之間是否有業(yè)務(wù)關(guān)系:
orders和items:
orders和items之間可以通過orderdetail表建立 關(guān)系。

3 一對(duì)一查詢

需求:
查詢訂單信息,關(guān)聯(lián)查詢創(chuàng)建訂單的用戶信息

sql語句:

SELECT orders.*,user.username,user.sex,user.address FROM USER,orders WHERE orders.user_id = user.id
image.png

一個(gè)訂單對(duì)應(yīng)一個(gè)用戶

3-1 方式一 resultType

1 創(chuàng)建pojo

將上邊sql查詢的結(jié)果映射到pojo中,pojo中必須包括所有查詢列名。原始的Orders.java不能映射全部字段,需要新創(chuàng)建的pojo。創(chuàng)建一個(gè)pojo繼承包括查詢字段較多的po類。

原始的Orders
新創(chuàng)建的pojo繼承Orders

2 mapper.xml

注意resultType="cn.itcast.mybatis.po.OrdersCustom與上面的pojo對(duì)應(yīng)

<select id="findOrdersUser" resultType="cn.itcast.mybatis.po.OrdersCustom">
        SELECT
        orders.*,
        USER.username,
        USER.sex,
        USER.address
        FROM
        orders,
        USER
        WHERE orders.user_id = user.id
</select>

3 mapper.java

public interface OrdersMapperCustom {

    //查詢訂單關(guān)聯(lián)查詢用戶信息
    public List<OrdersCustom> findOrdersUser()throws Exception;
}

4 測(cè)試代碼

統(tǒng)一前置

private SqlSessionFactory sqlSessionFactory;

    // 此方法是在執(zhí)行testFindUserById之前執(zhí)行
    @Before
    public void setUp() throws Exception {
        // 創(chuàng)建sqlSessionFactory

        // mybatis配置文件
        String resource = "SqlMapConfig.xml";
        // 得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
 @Test
    public void findOrdersUser() throws Exception{
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 創(chuàng)建代理對(duì)象
        OrdersMapperCustom ordersMapperCustom = sqlSession
                .getMapper(OrdersMapperCustom.class);

        // 調(diào)用maper的方法
        List<OrdersCustom> list = ordersMapperCustom.findOrdersUser();

        System.out.println(list);

        sqlSession.close();
    }

3-2 方式二resultMap

映射的思路:使用resultMap將查詢結(jié)果中的訂單信息映射到Orders對(duì)象中,在orders類中添加User屬性,將關(guān)聯(lián)查詢出來的用戶信息映射到orders對(duì)象中的user屬性中。

1 在Orders類中添加user屬性

image.png

2 mapper.xml中定義resultMap

這個(gè)很重要,替代上面的pojo類

<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">
        <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"/>

        <!-- 配置映射的關(guān)聯(lián)的用戶信息 -->
        <!-- association:用于映射關(guān)聯(lián)查詢單個(gè)對(duì)象的信息
        property:要將關(guān)聯(lián)查詢的用戶信息映射到Orders中哪個(gè)屬性
         -->
        <association property="user" javaType="cn.itcast.mybatis.po.User">
            <!-- id:關(guān)聯(lián)查詢用戶的唯 一標(biāo)識(shí)
            column:指定唯 一標(biāo)識(shí)用戶信息的列
            javaType:映射到user的哪個(gè)屬性
             -->
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
        </association>

    </resultMap>

3 mapper.java接口中定義方法
public List<Orders> findOrdersUserResultMap()throws Exception;

4 測(cè)試代碼

 @Test
    public void findOrdersUserResultMap() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();

        OrdersMapperCustom mapper = sqlSession.getMapper(OrdersMapperCustom.class);

        List<Orders> ordersUser = mapper.findOrdersUserResultMap();

        System.out.println(ordersUser);

        sqlSession.close();

    }

3-3 resultType和resultMap實(shí)現(xiàn)一對(duì)一查詢小結(jié)

實(shí)現(xiàn)一對(duì)一查詢:
resultType:使用resultType實(shí)現(xiàn)較為簡(jiǎn)單,如果pojo中沒有包括查詢出來的列名,需要增加列名對(duì)應(yīng)的屬性,即可完成映射。
如果沒有查詢結(jié)果的特殊要求建議使用resultType。

resultMap:需要單獨(dú)定義resultMap,實(shí)現(xiàn)有點(diǎn)麻煩,如果對(duì)查詢結(jié)果有特殊的要求,使用resultMap可以完成將關(guān)聯(lián)查詢映射pojo的屬性中。

resultMap可以實(shí)現(xiàn)延遲加載,resultType無法實(shí)現(xiàn)延遲加載。

4 多對(duì)多查詢

需求:查詢用戶及用戶購買商品信息

查詢主表是:用戶表
關(guān)聯(lián)表:由于用戶和商品沒有直接關(guān)聯(lián),通過訂單和訂單明細(xì)進(jìn)行關(guān)聯(lián),所以關(guān)聯(lián)表:
orders、orderdetail、items

SELECT 
  orders.*,
  USER.username,
  USER.sex,
  USER.address,
  orderdetail.id orderdetail_id,
  orderdetail.items_id,
  orderdetail.items_num,
  orderdetail.orders_id,
  items.name items_name,
  items.detail items_detail,
  items.price items_price
FROM
  orders,
  USER,
  orderdetail,
  items
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id

4-1 映射思路

將用戶信息映射到user中。
在user類中添加訂單列表屬性List<Orders> orderslist,將用戶創(chuàng)建的訂單映射到orderslist
在Orders中添加訂單明細(xì)列表屬性List<OrderDetail>orderdetials,將訂單的明細(xì)映射到orderdetials
在OrderDetail中添加Items屬性,將訂單明細(xì)所對(duì)應(yīng)的商品映射到Items。

4-2 pojo

image.png
image.png
image.png

4-3 mapper.xml

    <!-- 查詢用戶及購買的商品 -->
    <resultMap type="cn.itcast.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"/>

        <!-- 訂單信息
        一個(gè)用戶對(duì)應(yīng)多個(gè)訂單,使用collection映射
         -->
        <collection property="ordersList" ofType="cn.itcast.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"/>

            <!-- 訂單明細(xì)
        一個(gè)訂單包括 多個(gè)明細(xì)
         -->
            <collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
                <id column="orderdetail_id" property="id"/>
                <result column="items_id" property="itemsId"/>
                <result column="items_num" property="itemsNum"/>
                <result column="orders_id" property="ordersId"/>

                <!-- 商品信息
                 一個(gè)訂單明細(xì)對(duì)應(yīng)一個(gè)商品
                  -->
                <association property="items" javaType="cn.itcast.mybatis.po.Items">
                    <id column="items_id" property="id"/>
                    <result column="items_name" property="name"/>
                    <result column="items_detail" property="detail"/>
                    <result column="items_price" property="price"/>
                </association>
            </collection>
        </collection>
    </resultMap>

4-4 接口定義方法

//查詢用戶購買商品信息
public List<User>  findUserAndItemsResultMap()throws Exception;

4-5 測(cè)試類

    @Test
    public void findUserAndItemsResultMap() throws Exception{

        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 創(chuàng)建代理對(duì)象
        OrdersMapperCustom ordersMapperCustom = sqlSession
                .getMapper(OrdersMapperCustom.class);

        // 調(diào)用maper的方法
        List<User> list = ordersMapperCustom.findUserAndItemsResultMap();

        System.out.println(list);

        sqlSession.close();
    }

5 resultMap總結(jié)

resultType:
作用:
將查詢結(jié)果按照sql列名pojo屬性名一致性映射到pojo中。
場(chǎng)合:
常見一些明細(xì)記錄的展示,比如用戶購買商品明細(xì),將關(guān)聯(lián)查詢信息全部展示在頁面時(shí),此時(shí)可直接使用resultType將每一條記錄映射到pojo中,在前端頁面遍歷list(list中是pojo)即可。

resultMap:
使用association和collection完成一對(duì)一和一對(duì)多高級(jí)映射(對(duì)結(jié)果有特殊的映射要求)。

association:
作用:
將關(guān)聯(lián)查詢信息映射到一個(gè)pojo對(duì)象中。
場(chǎng)合:
為了方便查詢關(guān)聯(lián)信息可以使用association將關(guān)聯(lián)訂單信息映射為用戶對(duì)象的pojo屬性中,比如:查詢訂單及關(guān)聯(lián)用戶信息。
使用resultType無法將查詢結(jié)果映射到pojo對(duì)象的pojo屬性中,根據(jù)對(duì)結(jié)果集查詢遍歷的需要選擇使用resultType還是resultMap。

collection:
作用:
將關(guān)聯(lián)查詢信息映射到一個(gè)list集合中。
場(chǎng)合:
為了方便查詢遍歷關(guān)聯(lián)信息可以使用collection將關(guān)聯(lián)信息映射到list集合中,比如:查詢用戶權(quán)限范圍模塊及模塊下的菜單,可使用collection將模塊映射到模塊list中,將菜單列表映射到模塊對(duì)象的菜單list屬性中,這樣的作的目的也是方便對(duì)查詢結(jié)果集進(jìn)行遍歷查詢。
如果使用resultType無法將查詢結(jié)果映射到list集合中。

6 延遲加載

6-1 什么是延遲加載

resultMap可以實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一及一對(duì)多映射),association、collection具備延遲加載功能。
需求:
如果查詢訂單并且關(guān)聯(lián)查詢用戶信息。如果先查詢訂單信息即可滿足要求,當(dāng)我們需要查詢用戶信息時(shí)再查詢用戶信息。把對(duì)用戶信息的按需去查詢就是延遲加載。

延遲加載:先從單表查詢、需要時(shí)再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高 數(shù)據(jù)庫性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。

6-2 延遲加載配置

mybatis默認(rèn)沒有開啟延遲加載,需要在SqlMapConfig.xml中setting配置。

在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading

image.png

在SqlMapConfig.xml中配置:

    <settings>
        <!-- 打開延遲加載 的開關(guān) -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 將積極加載改為消極加載即按需要加載 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

6-3 使用association實(shí)現(xiàn)延遲加載

查詢訂單并且關(guān)聯(lián)查詢用戶信息

1 mapper.xml

需要定義兩個(gè)mapper的方法對(duì)應(yīng)的statement。

(1)只查詢訂單信息
SELECT * FROM orders
在查詢訂單的statement中使用association去延遲加載(執(zhí)行)下邊的satatement(關(guān)聯(lián)查詢用戶信息)

    <!-- 查詢訂單關(guān)聯(lián)查詢用戶,用戶信息需要延遲加載 -->
    <select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
        SELECT * FROM orders
    </select>

(2)關(guān)聯(lián)查詢用戶信息
通過上邊查詢到的訂單信息中user_id去關(guān)聯(lián)查詢用戶信息
使用association中的select指定延遲加載去執(zhí)行的statement的id。
使用UserMapper.xml中的findUserById

    <!-- 延遲加載的resultMap -->
    <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
        <!--對(duì)訂單信息進(jìn)行映射配置  -->
        <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"/>
        <!-- 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載
        select:指定延遲加載需要執(zhí)行的statement的id(是根據(jù)user_id查詢用戶信息的statement)
        要使用userMapper.xml中findUserById完成根據(jù)用戶id(user_id)用戶信息的查詢,如果findUserById不在本mapper中需要前邊加namespace
        column:訂單信息中關(guān)聯(lián)用戶信息查詢的列,是user_id
        關(guān)聯(lián)查詢的sql理解為:
        SELECT orders.*,
        (SELECT username FROM USER WHERE orders.user_id = user.id)username,
        (SELECT sex FROM USER WHERE orders.user_id = user.id)sex
         FROM orders
                 -->
        <association property="user"  javaType="cn.itcast.mybatis.po.User"
                     select="cn.itcast.mybatis.mapper.UserMapper.findUserId" column="user_id">
            <!-- 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載 -->
        </association>

    </resultMap>

上邊先去執(zhí)行findOrdersUserLazyLoading,當(dāng)需要去查詢用戶的時(shí)候再去執(zhí)行findUserById,通過resultMap的定義將延遲加載執(zhí)行配置起來。

2 測(cè)試

1、執(zhí)行上邊mapper方法(findOrdersUserLazyLoading),內(nèi)部去調(diào)用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查詢orders信息(單表)。

2、在程序中去遍歷上一步驟查詢出的List<Orders>,當(dāng)我們調(diào)用Orders中的getUser方法時(shí),開始進(jìn)行延遲加載。

3、延遲加載,去調(diào)用UserMapper.xml中findUserbyId這個(gè)方法獲取用戶信息。

代碼如下

    @Test
    public void testFindOrdersUserLazyLoading() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();// 創(chuàng)建代理對(duì)象
        OrdersMapperCustom ordersMapperCustom = sqlSession
                .getMapper(OrdersMapperCustom.class);
        // 查詢訂單信息(單表)
        List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();

        // 遍歷上邊的訂單列表
        for (Orders orders : list) {
            // 執(zhí)行g(shù)etUser()去查詢用戶信息,這里實(shí)現(xiàn)按需加載
            User user = orders.getUser();
            System.out.println(user);
        }

    }

6-4 延遲加載思考

不使用mybatis提供的association及collection中的延遲加載功能,如何實(shí)現(xiàn)延遲加載??

實(shí)現(xiàn)方法如下:
定義兩個(gè)mapper方法:
1、查詢訂單列表
2、根據(jù)用戶id查詢用戶信息
實(shí)現(xiàn)思路:
先去查詢第一個(gè)mapper方法,獲取訂單信息列表
在程序中(service),按需去調(diào)用第二個(gè)mapper方法去查詢用戶信息。

總之:
使用延遲加載方法,先去查詢簡(jiǎn)單的sql(最好單表,也可以關(guān)聯(lián)查詢),再去按需要加載關(guān)聯(lián)查詢的其它信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容