处理 Mybatis 中一对多、多对一、多对多映射的黑魔法

来源:互联网 发布:80端口入侵 编辑:程序博客网 时间:2024/05/01 16:50

前言

先看看Mybatis官方介绍

MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

注意,这里是简单的XML! 可是,当我们的数据库表关系错综复杂,表与表之存在一对多、多对一、多对多的关系时,如何通过mybatis表示出他们的关系呢?网上很多文章都在介绍 association、 collection,我先不说association、 collection有多好,先来看看一个具体实例。

下图是订单的数据库表关系


这里写图片描述


有这样一个需求,我要展示类似于淘宝订单的效果,如下图:


这里写图片描述


我们看到上面的订单就会想到,要展示一条订单,需要:订单信息、物流信息、卖家信息、买家信息、商品信息、商品属性信息、商品状态信息…,至少也要5/6张表的数据,其中,订单对买家/卖家是多对一关系、订单对商品时多对多关系…,看看类似的xml:

<!-- 查询用户及购买的商品  type写的是user类的全路径  把数据映射到user中   -->    <resultMap type="org.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" />        <!-- 订单信息一个用户对应多个订单,使用collection映射-->        <collection property="ordersList" ofType="org.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" />            <!-- 订单明细一个订单包括 多个明细  -->            <collection property="orderdetailList" ofType="org.mybatis.po.Orderdetail">                <id column="orderdetailid" property="id" />                <result column="orders_id" property="ordersId" />                <result column="items_id" property="itemsId" />                <result column="items_num" property="itemsNum" />                <!-- 商品信息一个订单明细对应一个商品-->                <association property="items" javaType="org.mybatis.po.Items">                    <id column="items_id" property="id"></id>                    <result column="name" property="name" />                    <result column="price" property="price" />                    <result column="detail" property="detail" />                </association>            </collection>        </collection>        ...        <!--还有卖家、买家、物流...-->        ...

仅仅这一个订单,如果用association、 collection来实现,xml何其多、何其复杂!除了xml,还有一堆实体类要写,写着写着很容易乱!这跟Mybatis官网上说的简单xml相悖,我想要的效果是简简单单的像一个实体类就能映射的xml,任何人,无论是初学者还是老程序员都能一眼直观的xml。

抛砖引玉

那么,要怎样将订单的xml简化,我先来一个抛砖引玉,mybatis和hibernate最大的区别是什么?


Mybatis可以更细致的定制化! hibernate 具体更强的移植性和缓存机制。既然说Mybatis可以更细致的定制化,如何定制!通过sql优化、sql定制,既然sql可以根据具体的需求而定,那么我可以利用sql处理数据库表的关系,只需要返回直观的结果给我就行。一言蔽之,就是:把一对多、多对一、多对多关系扔到sql中去处理,xml只需要接收最直接、最简单的数据即可!


好,回到订单,显示一个订单需要哪些信息,需要如下信息:

public class OrderInfo {    //订单id    private Integer id;     //订单价格    private Integer price;    //订单生成时间    private Date createdTime;    //订单状态    private Integer status;    //商品数量    private Integer util;    //买家电话    private String phone;    //买家名字    private String userName;    //物流地址    private String receiverAddress;    //支付方式    private String payName;    //商品名称    private String productName;    //商品属性    private String standard;    //卖家名称    private String marketName;    //商品缩略图    private String productPhoto;    setter and getter...


xml怎么写? 我不需要association、 collection就可以实现,把数据库关系交给数据库处理,我用最原始的and 表示(这里以mysql为例)

... <select id="selectOrderInfoByOrderId" resultType="com.vbtime.thor.wrapper.OrderInfo" parameterType="java.lang.Integer">    select o.id as id, o.status as status, o.price as price,o.created_time as createdTime, o.util as util, u.name as userName, u.phone as phone, r.receiver_address as receiverAddress, pay.name as payName,        group_concat(concat(ps.name,':',psv.value) Separator ';')  as standard, m.name as marketName,p.name as productName,p.photo as productPhoto        from  rorder o, order_standard_value os, product_standard ps, product_standard_values psv, user u, product p, market m, order_market om, order_product op, pay_type pay, receiver r where        u.id = o.user_id and p.id = op.product_id and o.id = op.order_id and m.id= om.market_id and o.id = om.order_id and o.id = os.order_id and psv.id = os.standard_value_id and         ps.id= psv.product_standard_id and pay.id = o.pay_id and r.id = o.recevier_id and o.id = #{orderId} </select> ...


测试一下sql


这里写图片描述

说明一下,以商品的属性为例,商品属性有多个,颜色、尺码、材质、外观… 可以用mysql的group_concat() 和 concat() 函数将多行属性转化为订单的一列,多个属性之间可以用“;”或“//”分割,方便客户端处理。


总结

用sql处理数据库关系有3点好处:

  • 减少xml复杂度,代码简洁可读性强

  • xml返回的数据跟实际业务需要的数据差不多,可以直接返回给客户端

  • 充分发挥数据库本身的优势,有人说用sql语句处理表的关系,移植性差,其实mybatis本身是基于sql的,本来移植性就差,干脆我们使它差,为了偷懒!

原创粉丝点击