4、訂單商品數(shù)據(jù)模型映射(1)(mybatis筆記)

主要內(nèi)容:

  • 開發(fā)中數(shù)據(jù)模型的分析流程
  • 一對一查詢
  • 一對多查詢

一、開發(fā)中數(shù)據(jù)模型的分析流程

一般在開發(fā)中我們會直接拿到相關(guān)的數(shù)據(jù)庫,此時我們需要對數(shù)據(jù)模型進行分析之后,才能進行相關(guān)的開發(fā)。

1.1 分析思路

  • (1)每張表記錄的數(shù)據(jù)內(nèi)容
    在企業(yè)中分模塊對每張表記錄的內(nèi)容進行熟悉,這相當(dāng)于學(xué)習(xí)系統(tǒng)需求(功能)的過程。
  • (2)每張表數(shù)據(jù)庫重要字段的設(shè)置
    重點查看那每張表中的非空字段和外鍵字段,這屬于比較重要的字段。
  • (3)數(shù)據(jù)庫級別表之間的關(guān)系
    數(shù)據(jù)庫級別表之間的關(guān)系指的就是表之間的外鍵關(guān)系。
  • (4)表與表的業(yè)務(wù)關(guān)系
    在分析表和表之間的業(yè)務(wù)關(guān)系一定要建立在某個業(yè)務(wù)意義基礎(chǔ)之上,不能單純的說是一對多或一對一關(guān)系。

1.2 模型分析

1.2.1 數(shù)據(jù)模型

這里我們先給出本例子中所要用到的相關(guān)表:

  • 用戶表,在之前已經(jīng)給出了
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用戶名稱',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性別',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8
  • 訂單表
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下單用戶id',
  `number` varchar(32) NOT NULL COMMENT '訂單號',
  `createtime` datetime NOT NULL COMMENT '創(chuàng)建訂單時間',
  `note` varchar(100) DEFAULT NULL COMMENT '備注',
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
  • 訂單明細表
CREATE TABLE `orderdetail` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) NOT NULL COMMENT '訂單id',
  `items_id` int(11) NOT NULL COMMENT '商品id',
  `items_num` int(11) DEFAULT NULL COMMENT '商品購買數(shù)量',
  PRIMARY KEY (`id`),
  KEY `FK_orderdetail_1` (`orders_id`),
  KEY `FK_orderdetail_2` (`items_id`),
  CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
  • 商品表
CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '商品名稱',
  `price` float(10,1) NOT NULL COMMENT '商品定價',
  `detail` text COMMENT '商品描述',
  `pic` varchar(64) DEFAULT NULL COMMENT '商品圖片',
  `createtime` datetime NOT NULL COMMENT '生產(chǎn)日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

1.2.2 模型分析

1.2.2.1 單張表分析

  • 用戶表user:記錄了購買商品的用戶信息
    比較重要的字段就是其自增主鍵id

  • 訂單表orders:記錄了用戶所創(chuàng)建的訂單(購買商品的訂單)
    比較重要的字段就是其中的訂單號number和外鍵user_id

  • 訂單明細表orderdetail:記錄了訂單的詳細信息即訂單中所包含的一些商品信息。
    比較重要的字段就是自增主鍵id,外鍵orders_id和外鍵items_id

  • 商品信息表items:記錄了用戶所購買的商品信息
    比較重要的字段就是自增主鍵id

1.2.2.2 表與表之間的業(yè)務(wù)關(guān)系

(1)先分析數(shù)據(jù)庫級別有關(guān)系之間的業(yè)務(wù)關(guān)系

  • 用戶表(user)和訂單表(orders
    user-->orders:一個用戶可以創(chuàng)建多個訂單,一對多
    orders-->user:一個訂單只由一個用戶來創(chuàng)建,一對一

  • 訂單表(orders)和訂單明細表(ordredetail
    orders-->orderdetail:一個訂單可以包括多個訂單明細,因為一個訂單可以購買多個商品,每個商品的購買信息在ordredetail記錄,一對多關(guān)系
    ordredetail-->orders:一個訂單明細只能包括在一個訂單中,一對一

  • 訂單明細表(orderdetail)和商品表(items
    orderdetail-->items:一個訂單明細只對應(yīng)一個商品信息,一對一關(guān)系
    items-->orderdetail:一個商品對應(yīng)多個明細,一對多

(2)再分析數(shù)據(jù)庫級別沒有關(guān)系的表之間是否有業(yè)務(wù)關(guān)系

  • ordersitems:可以通過orderdetail建立關(guān)系
    orders-->items:一對多
    items-->orders:一對多
    也就是多對多關(guān)系。

  • useritems
    user-->items:一對多
    items-->user:一對多
    也就是多對多關(guān)系

注意:這里我們的多有關(guān)系在分析的時候都必須建立在相關(guān)實際業(yè)務(wù)基礎(chǔ)之上。

二、一對一關(guān)系映射

2.1 需求

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

2.2 resultType實現(xiàn)(工程mybatis08

  • sql語句
    • 確定查詢的主表:orders
    • 確定查詢的關(guān)聯(lián)表:user
    • 關(guān)聯(lián)查詢使用內(nèi)連接還是外連接?
      由于在orders中有一個外鍵(user_id),通過外鍵來關(guān)聯(lián)查詢用戶表只能查詢出一條記錄,可以使用內(nèi)連接。
SELECT  orders.*, user.username, user.sex, user.address 
FROM  orders , USER 
WHERE  orders.user_id = user.id
  • 創(chuàng)建pojo
    這里我們使用resultType的方式實現(xiàn),我們需要對訂單pojo進行增強。
    orders.java
public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
.......
}

OrdersCustom.java

public class OrdersCustom extends Orders {
    private String username;// 用戶名稱
    private String address;// 用戶地址
    private String sex ;//性別
.......
}

說明:將上面sql查詢到的結(jié)果集映射到pojo中,pojo中必須要包括所有的查詢列名。原始的orders.java不能映射全部字段,需要創(chuàng)建一個pojo,讓其繼承包括查詢字段較多的那個pojo類。

  • 編寫mapper.xml
    OrdersCustomMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.itcast.mapper.OrdersCustomMapper">

    <!-- 查詢訂單關(guān)聯(lián)查詢用戶 -->
    <select id="findOrdersUser" resultType="OrdersCustom">
        SELECT orders.*, user.username, user.sex, user.address
        FROM orders , USER
        WHERE orders.user_id = user.id
    </select>
</mapper>
  • 接口mapper.java
    OrdersCustomMapper.java
package cn.itcast.mapper;
import java.util.List;
import cn.itcast.pojo.OrdersCustom;

//訂單mapper
public interface OrdersCustomMapper {
    public List<OrdersCustom> findOrdersUser() throws Exception;
}
  • 測試
    OrdersCustomMapperTest.java
package cn.itcast.mapper;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.pojo.OrdersCustom;
public class OrdersCustomMapperTest {
    
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setUp() throws Exception {
        // 創(chuàng)建sqlSessionFactory
        // mybatis配置文件
        String resource = "SqlMapConfig.xml";
        // 得到配置文件流
        InputStream is = Resources.getResourceAsStream(resource);
        // 創(chuàng)建會話工廠,要想build方法中傳入配置信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    }
    
    @Test
    public void testFindOrdersCustoms() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //創(chuàng)建代理對象
        OrdersCustomMapper ordersCustom = sqlSession.getMapper(OrdersCustomMapper.class);
        //調(diào)用mapper的方法
        List<OrdersCustom> list = ordersCustom.findOrdersUser();
        System.out.println(list.size());
        sqlSession.close();
    }
}

2.3 resultMap實現(xiàn)(工程mybatis09

  • sql語句
    其中sql語句和之前的一樣。

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

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    //用戶信息
    private User user ;
......
}
  • 定義mapper.xml
    OrdersMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.itcast.mapper.OrdersMapper">
    
    <!-- 訂單查詢關(guān)聯(lián)查詢用戶的resultMap,即將整個查詢的結(jié)果映射到orders中 -->
    <resultMap type="Orders" id="OrdersUserResultMap">
        <!-- 配置要映射的訂單信息,如果有多個列組成唯一標(biāo)識,那需要配置多個id,
        property指定將唯一表示映射到pojo中的哪個屬性上 -->
        <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)的用戶信息,用于映射關(guān)聯(lián)查詢單個對象的信息,
        property表示要將關(guān)聯(lián)查詢的用戶信息映射到orders中的哪個屬性 -->
        <association property="user" javaType="User">
            <!-- id:關(guān)聯(lián)查詢用戶的唯一表示
            column:指定用于唯一表示用戶信息的列
            javaType:映射到User的哪個屬性 -->
            <id column="user_id" property="id"/>
            <result column="" property="note"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>
    
    <!-- 查詢訂單關(guān)聯(lián)查詢用戶,使用resultMap -->
    <select id="findOrdersUser" resultMap="OrdersUserResultMap">
        SELECT orders.*, user.username, user.sex, user.address
        FROM orders , USER
        WHERE orders.user_id = user.id
    </select>
</mapper>
  • 接口OrdersMapper.java
package cn.itcast.mapper;
import java.util.List;
import cn.itcast.pojo.Orders;

//訂單mapper
public interface OrdersMapper {
    public List<Orders> findOrdersUser() throws Exception;
}
  • 測試
    OrdersMapperTest.java
    @Test
    public void testFindOrdersUser() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //創(chuàng)建代理對象
        OrdersMapper orders = sqlSession.getMapper(OrdersMapper.class);
        //調(diào)用mapper的方法
        List<Orders> list = orders.findOrdersUser();
        System.out.println(list.size());
        sqlSession.close();
    }

2.4 resultMap 和 resultType 小結(jié)

實現(xiàn)一對一查詢時

  • resultType此種方式較為簡單,如果pojo中沒有包括查詢出來的列名,需要增加列名對應(yīng)的屬性,即可完成映射。如果沒有查詢結(jié)果的特殊要求建議使用此種方式。

  • resultMap如果對查詢結(jié)果有特殊的要求則推薦使用此種方式??梢詫崿F(xiàn)延遲加載。而resultType則不能實現(xiàn)延遲加載。

三、一對多關(guān)系映射(工程mybatis10

3.1需求

查詢訂單及訂單明細的信息,保留用戶信息

3.2 sql語句

  • 確定主查詢表:訂單表
  • 確定關(guān)聯(lián)查詢表:訂單明細表
  • 在一對一查詢基礎(chǔ)上,添加訂單明細表關(guān)聯(lián)即可,這種方式使用內(nèi)連接顯示的是多的一方的數(shù)據(jù),有重復(fù)。
SELECT 
    orders.*, 
    user.username, 
    user.sex,
    user.address,
    orderdetail.items_id,
    orderdetail.id orderdetail_id,
    orderdetail.items_num,
    orderdetail.orders_id
FROM 
    orders , USER , orderdetail
WHERE 
    orders.user_id = user.id AND orderdetail.orders_id = orders.id

說明:這里之所以要將訂單明細的id起別名,是因為在映射文件中映射的時候會和訂單id重復(fù)。

3.3 使用resultType

此時這種方式將上邊的查詢結(jié)果映射到pojo中,訂單信息就會有重復(fù)

1

當(dāng)然我們還是可以使用此種方式的,如果要實現(xiàn)不重復(fù),則在將訂單明細映射到Orders.java中的orderDetails中,需要自己處理,使用遍歷,去掉重復(fù)記錄,將訂單明細存儲在List中,但顯然有點麻煩。這里我們使用resultMap。

3.4 使用 resultMap

要求是對orders映射不能出現(xiàn)重復(fù)記錄。于是我們在Orders.java中添加一個屬性List<orderDetail> orderDetails屬性,最終會將訂單信息映射到orders中,訂單所對應(yīng)的訂單明細就會映射到Orders.java中的orderDetails屬性中。映射成的orders的記錄數(shù)為兩條,不重復(fù),而每個Orders.java中的orderDetail屬性存儲了該訂單所對應(yīng)的訂單明細。

3.4.1 mapper.xml

OrdersMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.itcast.mapper.OrdersMapper">

    <!-- 訂單查詢關(guān)聯(lián)查詢用戶的resultMap,即將整個查詢的結(jié)果映射到orders中 -->
    <resultMap type="Orders" id="OrdersUserResultMap">
        <!-- 配置要映射的訂單信息,如果有多個列組成唯一標(biāo)識,那需要配置多個id,
        property指定將唯一表示映射到pojo中的哪個屬性上 -->
        <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)的用戶信息,用于映射關(guān)聯(lián)查詢單個對象的信息,
        property表示要將關(guān)聯(lián)查詢的用戶信息映射到orders中的哪個屬性 -->
        <association property="user" javaType="User">
            <!-- id:關(guān)聯(lián)查詢用戶的唯一表示
            column:指定用于唯一表示用戶信息的列
            javaType:映射到User的哪個屬性 -->
            <id column="user_id" property="id"/>
            <result column="" property="note"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>

    <!-- 查詢訂單和訂單明細的resultMap -->
    <resultMap type="Orders" id="OrdersAndOrderdetailResultMap" extends="OrdersUserResultMap">
        <!-- 很明顯這里的訂單信息和用戶信息和上面的重復(fù),我們可以使用繼承 -->
        <!-- 訂單信息 -->
        <!-- 用戶信息 -->
    
        <!-- 訂單明細信息,一個訂單查詢出了多個訂單明細,要是用collection進行映射
        collection:對關(guān)聯(lián)查詢到多條記錄映射到集合中
        property:映射到orders類中的哪個屬性
        ofType:要映射到集合中pojo的屬性 -->
        <collection property="orderdetails" ofType="Orderdetail">
            <!-- id:訂單明細的唯一標(biāo)識,property:要將訂單明細的唯一標(biāo)識映射到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"/>
            <result column="items_id" property="itemsId"/>
            
        </collection>
    </resultMap>
    
    
    <!-- 查詢訂單關(guān)聯(lián)查詢用戶以及訂單明細,使用resultMap -->
    <select id="findOrdersAndOrderdetail" resultMap="OrdersAndOrderdetailResultMap">
        SELECT  orders.*, user.username, user.sex,user.address, orderdetail.id orderdetail_id,
                orderdetail.items_id, orderdetail.items_num, orderdetail.orders_id
        FROM orders , USER , orderdetail
        WHERE orders.user_id = user.id AND orderdetail.orders_id = orders.id

    </select>
    
    <!-- 查詢訂單關(guān)聯(lián)查詢用戶,使用resultMap -->
    <select id="findOrdersUser" resultMap="OrdersUserResultMap">
        SELECT orders.*, user.username, user.sex, user.address
        FROM orders , USER
        WHERE orders.user_id = user.id
    </select>
</mapper>

說明:我們在映射訂單明細的唯一標(biāo)識的時候需要使用一個字段,如果直接使用訂單明細的id,則會和訂單表的id重復(fù),于是我們給此字段起了一個別名。

3.4.2 mapper.java

OrdersMapper.java

package cn.itcast.mapper;
import java.util.List;
import cn.itcast.pojo.Orders;

//訂單mapper
public interface OrdersMapper {
    public List<Orders> findOrdersUser() throws Exception;

    //查詢訂單和訂單明細,保留了關(guān)聯(lián)用戶
    public List<Orders> findOrdersAndOrderdetail() throws Exception;
}

3.4.3 測試

OrdersMapperTest.java

    @Test
    public void testFindOrdersAndOrderdetail() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //創(chuàng)建代理對象
        OrdersMapper orders = sqlSession.getMapper(OrdersMapper.class);
        //調(diào)用mapper的方法
        List<Orders> list = orders.findOrdersAndOrderdetail();
        System.out.println(list.size());
        
        sqlSession.close();
    }

說明:使用斷點調(diào)試方式可以查看結(jié)果,我們發(fā)現(xiàn)確實值有兩條訂單記錄,而每條訂單記錄中有兩條訂單明細記錄,這樣就很好的去除了重復(fù)。

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

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

  • 這里我們說明如何進行多對多關(guān)聯(lián)映射。(工程mybatis11) 一、需求 查詢用戶及用戶所購買的商品信息。 二、分...
    yjaal閱讀 1,753評論 0 1
  • 轉(zhuǎn)載,覺得這篇寫 SQLAlchemy Core,寫得非常不錯。不過后續(xù)他沒寫SQLAlchemy ORM... ...
    非夢nj閱讀 5,608評論 1 14
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評論 19 139
  • 非本人總結(jié)的筆記,抄點筆記復(fù)習(xí)復(fù)習(xí)。感謝傳智博客及黑馬程序猿成長 關(guān)聯(lián)查詢 數(shù)據(jù)中的表結(jié)構(gòu) 數(shù)據(jù)庫的分析方法 第一...
    鍵盤瞎閱讀 1,162評論 3 5
  • CREATE TABLE IF NOT EXISTS ecs_order_info (order_id mediu...
    cookie口閱讀 16,158評論 0 16

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