【MyBatis学习12】多对多关联

本文博客地址:http://blog.csdn.net/soonfly/article/details/63689420 (转载请注明出处)

这篇说多对多关系。多对多其实就是一对多的组合关系。
回忆前文中几个重要的关系:
1、1个用户可以有0个或多个订单:[user表]–>[order表]是1对多(0.n)关系
2、1个有效订单会购买1条或多条商品分录:[order表]–>[order_detail表]是1对多(1.n)关系
3、1条商品分录必定对应一个产品详情:[order_detail表]–>[product表]是1对1关系
用户购买记录中可以有多个商品,而一个商品可以被多个用户购买,这就是多对多关系。

一般说来,两个1对多关系组合在一起就是多对多,如:
[user表]–>[order表]是1对多,[order表]–>[order_detail表]是1对多,那么[user表]–>[order_detail表–Product表]就是多对多。

站在一端思考就很简单。比如从用户角度出发,那么在用户的后台中,看自己买过哪些东西,这就是多对多的一种应用。如果站在商品角度出发,那么可以分析该商品被哪些用户购买过。

我们从用户角度出发分析:
从用户到商品,涉及到四表联查,其关系如下:
这里写图片描述
说明:因为在订单明细表中对商品的相关字段做了冗余存储(起一个快照作用),本来可以不再关联查询product表。
这里为了描述多表联查的常见嵌套关系,所以不使用OrderDetail中的冗余字段,依旧关联查询product表。
四表联查:

SELECT `user`.username,`user`.address,`user`.cellphone,
    `order`.`orderno`,`order`.`totalprice`,`order`.`create_time`,
    `order_detail`.num,
    `product`.`productname`,`product`.`price`
    FROM `order` ,`user`,`order_detail`,`product` 
    WHERE `user`.id=`order`.create_userid AND
    `order`.id=`order_detail`.`order_id` AND 
    `order_detail`.`product_id`=`product`.`id` 

step1:将用户信息映射到User中;
在User类中添加订单列表属性List<Order> orderlist;,将用户创建的订单映射到orderlist中;
在Order中添加订单明细列表属性List<OrderDetail> orderdetailList;,将订单的明细映射到orderdetailList中;
在OrderDetail中添加Product product;属性,将订单明细所对应的商品映射到product中。
为了减少篇幅一些不相关的属性就没有写了,比如user中的password,salt,sex

step2:编写接口
接口UserMapper.java

public User selectDetailById(int id) throws Exception;

UserMapper.xml:
新增resultMap映射:

<resultMap id="user_contain_OrderList_Map" type="twm.mybatisdemo.pojo.User">
    <id column="id" property="id" />
    <result property="username" column="username" javaType="String"
        jdbcType="VARCHAR"></result>
    <result property="cellphone" column="cellphone" javaType="String"
        jdbcType="VARCHAR"></result>
    <result property="address" column="address" javaType="String"
        jdbcType="VARCHAR"></result>
    <!-- 第一个嵌套关系collection -->
    <collection property="orderlist" ofType="Order">
        <id column="orderid" property="id" />
        <result column="orderno" property="orderno" />
        <result column="totalprice" property="totalprice" />
        <result column="create_time" property="create_time" />
        <!-- 第二个嵌套关系collection -->
        <collection property="orderdetailList" ofType="OrderDetail">
            <id column="order_detailid" property="id" />
            <result column="num" property="num" />
            <!-- 第三个嵌套关系association -->
            <association property="product" javaType="Product">
                <id column="productid" property="id" />
                <result column="productname" property="productname" />
                <result column="price" property="price" />
            </association>
        </collection>
    </collection>
</resultMap>

注意:映射中的每一层都要指定主键,否则会发生无法distinct去重的情况;且一定不能有重名的id主键。
所以子查询中的主键,都另起了一个别名。

新增select片段:

<select id="selectDetailById" parameterType="int"
    resultMap="user_contain_OrderList_Map">
    SELECT `user`.`id`,`user`.username,`user`.address,`user`.cellphone,
    `order`.`id` AS `orderid`,`order`.`orderno`,`order`.`totalprice`,`order`.`create_time`,
    `order_detail`.`id` AS `order_detailid`,`order_detail`.num,
    `product`.`id` AS productid,`product`.`productname`,`product`.`price`
    FROM `order` ,`user`,`order_detail`,`product`
    WHERE `user`.id=`order`.create_userid AND
    `order`.id=`order_detail`.`order_id` AND
    `order_detail`.`product_id`=`product`.`id` AND 
    `user`.id=#{id}
</select>

step3:调用

public static void main(String[] args) throws Exception {
        SqlSession session = SqlSessionAssist.getSession();

        UserMapper usermapper = session.getMapper(UserMapper.class);
        User user = usermapper.selectDetailById(86);
        System.out.println("用户:"+user.getUsername() + ","
                + user.getAddress() + ","
                + user.getCellphone());
        List<Order> orderList=user.getOrderlist();
        for (Order order : orderList) {
            System.out.println("订单号:"+order.getOrderno());
            List<OrderDetail> orderdetailList=order.getOrderdetailList();
            for (OrderDetail orderdetail : orderdetailList) {
                System.out.println(orderdetail.getNum()+ "个,商品:"
                        + orderdetail.getProduct().getProductname() + ",单价:"
                        + orderdetail.getProduct().getPrice());

            }
        }

    }

这里同样可以将每一个,标签使用延迟加载来实现。
当然对于查询表格中要用到多个表字段的场景,这样依然会产生N+1查询的问题。

**总的来说:**Mybatis是半自动的,给了让大家书写SQL的机会,就是想让我们自己来把握效率。因此对于查询结果用到多表字段,尽量用SQL跨表联查的方式实现。对于查询结果只用到单表字段,采用延迟加载,会很方便简单。

本文博客地址:http://blog.csdn.net/soonfly/article/details/63689420 (转载请注明出处)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值