Mybatis嵌套映射(association)丢失数据的问题排查

发布时间 2023-12-07 09:47:08作者: 糖醋小灰

背景

项目过程中使用了Mybatis-Plus,由于存在连表查询的需求,还是选择在xml中写SQL

需求是根据前端传的不同状态去联查不同的表,返回值是一对一嵌套的类(使用association)

初步排查

简化后的SQL如下

<!--列表查询-->
    <select id="listPage"
            resultMap="tableMap">
        SELECT
        <include refid="TABLE_1"/>
        <if test="request.status != null">
            <trim prefix=",">
            <choose>
                <when test="request.status == 10">
                    <include refid="TABLE_2"/>
            </choose>
            </trim>
        </if>
        FROM TABLE_1 i
        <if test="request.status!= null">
            <choose>
                <when test="request.status == 10">
                    LEFT JOIN TABLE_2 t ON i.id = t.pro_id
                </when>
            </choose>
        </if>
    </select>

简化后的resultMap如下,大致字段如下,实际上还有很多字段

 <resultMap id="projectMap"
               type="TABLE_1"
               autoMapping="true">
        <!-- type:实体类名,如不定义别名需写全类名 -->
        <!--column是数据库表的字段名,property是实体的属性名-->
        <id column="row"/>
        <result column="id" property="id"/>
        <result column="proNo" property="proNo"/>
         …………………………………………………………………………
        <result column="createTime" property="createTime"/>
        <result column="createUser" property="createUser"/>
        <result column="updateTime" property="updateTime"/>
        <result column="updateUser" property="updateUser"/>
        <!--projectTalking-->
        <association property="TABLE_2"
                     javaType="TABLE_2">
            <id column="talkingId" property="id"/>
            ………………………………
        </association>


    </resultMap>  

 

在这样联查后,由于主表(TABLE_1)会关联多条(TABLE_2)的数据,但是为了方便分页与单条返回,所以做了一对一的映射,或许由于TABLE_1的字段大都相同,导致Mybatis认为数据是一样的,当TABLE_2存在多条数据时,明明给TABLE_2设置了id_column(存疑的一点,网上基本都说设置了ID就不会存在这种问题),但是返回值都只有一条,这边也尝试了删除TABLE_1的ID,只留下TABLE_2,但是同样无效。

问题定位

暂时认为是主表字段过多,导致相似度过高的原因(希望有大佬能解答)

这边采用了给每一条数据增加row_number的方法,使得每一条数据有不同的标识(由于是MySQL5.7,如果是8的话直接用RANK()就可以了)

<!--列表查询-->
    <select id="listPage"
            resultMap="tableMap">
        SELECT
        @i:= @i+ 1 AS `row`,
        <include refid="TABLE_1"/>
        <if test="request.status != null">
            <trim prefix=",">
            <choose>
                <when test="request.status == 10">
                    <include refid="TABLE_2"/>
            </choose>
            </trim>
        </if>
        FROM TABLE_1 i
        <if test="request.status!= null">
            <choose>
                <when test="request.status == 10">
                    LEFT JOIN TABLE_2 t ON i.id = t.pro_id
                </when>
            </choose>
        </if>
        ,( SELECT @i:= 0 ) r
    </select>