本文博客地址:http://blog.youkuaiyun.com/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.youkuaiyun.com/soonfly/article/details/63689420 (转载请注明出处)