跳到主要内容

其他解决方案的问题

上一篇文档中,我们讨论了动态查询。本目录中,我们将探讨动态表链接的问题

目前其他操作SQL的技术方案,无论ORM还是非ORM,都有存在一个空白领域:只考虑到了动态where,没有考虑动态join

动态JOIN定义:如果某些动态查询条件针对其他表而非当前表。这意味着

  • 条件满足时:先通过关联属性join到其他表,再对join得到的表添加动态where条件

  • 条件不满足时:不能通过关联属性join其他表

场景-1

让我们先来看第一个场景,这里用面向原生SQL的MyBatis为例

  • 定义MyBatis Mapper接口

    @Mapper
    public interface BookMapper {

    List<Book> findBooks(
    @Nullable String name,
    @Nullable String storeName,
    @Nullable String storeWebsite
    );
    }

    这里,所有查询参数都可能为null,很明显,这是一个动态查询。

    后面两个查询参数:storeNamestoreWebsite,其过滤条件并不施加在当前表BOOK上,而是施加在父表BOOK_STORE上。 即,当这两个参数中的任何一个非null时,都会生成对BOOK_STORE表的JOIN,这种由参数值动态决定是否添加的表连接,在本文中被称为动态JOIN

  • 定义MyBatis的SQL映射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="somepackage.BookMapper">
    <select id="findBooks" resultType="somepackage.Book">
    select * from BOOK as book
    <if test="storeName != null or storeWebsite != null">
    inner join BOOK_STORE as store
    on book.STORE_ID = store.ID
    </if>
    <where>
    <if test="name != null">
    and book.NAME = #{name}
    </if>
    <if test="storeName != null">
    and store.NAME = #{storeName}
    </if>
    <if test="storeWebsite != null">
    and store.WEBSITE = #{storeWebsite} ❸
    </if>
    </where>
    </select>
    </mapper>

    其中,❶就是动态JOIN。然而对开发人员而言,❷和❸才是目的,❶是为支持❷和❸而不得不做的工作,其判断条件是一种负担。

    也许你已经注意到了,❶的判断条件使用了or,这也不难理解。

    然而,这仅仅是最简单的两表之间动态连接,对于更深的多表连接操作而言,动态连接的复杂度会急剧上升!

场景-2

让我们再来看第二个场景,有了前面的例子作为基础,这个例子就不同任何业务耦合了。

<?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="somepackage.AMapper">
<select id="findAObjects" resultType="somepackage.A">
select distinct A.id
from A
<if test="bId != null or cId != null or dId != null or eId != null">
inner join B on A.ID = B.A_ID
</if>
<if test="cId != null or dId != null or eId != null">
inner join C on B.ID = C.B_ID
</if>
<if test="dId != null or eId != null">
inner join D on C.ID = D.C_ID
</if>
<if test="eId != null">
inner join E on D.ID = E.D_ID
</if>
<where>
<if test="aId != null">
and A.ID = #{aId}
</if>
<if test="bId != null">
and B.ID = #{bId}
</if>
<if test="cId != null">
and C.ID = #{cId}
</if>
<if test="dId != null">
and D.ID = #{dId}
</if>
<if test="eId != null">
and E.ID = #{eId}
</if>
</where>
</select>
</mapper>

这个例子逻辑很简单,A、B、C、D和E这五张表形成了一个JOIN链,每张表都一个动态查询条件。然而,正如你所见,动态JOIN的复杂度已经变得不可接受了。