MyBatis一对多关联查询与分步查询

假设有两种表,分别为用户表tb_user,用户人脸照片表tb_face。一个用户可能对应多张人脸照片。在查询用户的时候,需要将人脸照片数据一起查询出来。

数据库表结构:

表一(tb_user)

字段 类型 默认值 允许NULL 主键 外键 备注
client_id int NN PK
group_id varchar(32) NN PK
user_id varchar(32) NN PK
user_info varchar(200)
create_time datetime

表二(tb_face)

字段 类型 默认值 允许NULL 主键 外键 备注
face_id bigint NN PK AI
client_id int NN
group_id varchar(32) NN
user_id varchar(32) NN
face_token varchar(32) NN UQ
image mediumtext NN
create_time datetime NN

tb_face表与tb_user表的关联字段为:client_id、group_id、user_id。

Java实体类

实体类一(UserEntity)

@TableName("tb_user")
public class UserEntity {
    private int clientId;
  
    private String groupId;

    private String userId;

    private String userInfo;

    protected Date createTime;

    private List<FaceEntity> faceEntityList;

    // ... 省略setter/getter
}

faceEntityList 就是从tb_user表中关联出来的tb_face数据。

实体类二(FaceEntity)

@TableName("tb_face")
public class FaceEntity {
    private long faceId;

    private int clientId;

    private String groupId;

    private String userId;

    private String faceToken;

    private String image;

    protected Date createTime;

    // ... 省略setter/getter
}

实现这种一对多的关联查询有两个方式,一种是关联查询,一种是分步查询。

1、先看关联查询的MyBatis写法:

UserDao.xml

<resultMap id="userFaceResultMap" type="UserEntity">
        <id column="client_id" property="clientId"/>
        <id column="group_id" property="groupId"/>
        <id column="user_id" property="userId"/>
        <result column="user_info" property="userInfo"/>
        <result column="create_time" property="createTime"/>
        <collection property="faceEntityList" ofType="FaceEntity">
            <id column="face_id" property="faceId"/>
            <result column="client_id" property="clientId"/>
            <result column="group_id" property="groupId"/>
            <result column="user_id" property="userId"/>
            <result column="face_token" property="faceToken"/>
            <result column="image" property="image"/>
            <result column="face_create_time" property="createTime"/>
        </collection>
    </resultMap>

    <select id="queryUserFaceList" resultMap="userFaceResultMap">
        SELECT u.client_id,u.group_id,u.user_id,u.user_info,u.create_time,
        f.face_id,f.face_token,f.image,f.create_time AS face_create_time
        FROM tb_user u LEFT JOIN tb_face f
        ON(u.client_id=f.client_id AND u.group_id=f.group_id AND u.user_id=f.user_id)
        WHERE u.client_id=#{clientId} AND u.group_id=#{groupId}
    </select>

这种关联查询方式需要注意,t_face表查询的resultMap一定要定义一个id,并且这个id的名称在查询的列表中只能有一个,如果两个表之间id重名,必须使用别名。从SQL我们看到t_user表有create_time,t_face表也有create_time,因此给t_face表的create_time定义了一个别名叫face_create_time。

在resultMap中定义的id,可以看成是关联字段,如果查询结果出现id字段名称重复就会导致关联出来的数据与直接执行SQL时看到的结果不一样,往往只出现一条数据。

2、再看分步查询的MyBatis写法:

先在UserDao.xml中编写t_user的查询

<resultMap id="userFaceResultMap" type="UserEntity">
        <id column="client_id" property="clientId"/>
        <id column="group_id" property="groupId"/>
        <id column="user_id" property="userId"/>
        <result column="user_info" property="userInfo"/>
        <result column="create_time" property="createTime"/>
        <collection property="faceEntityList"
                    column="{clientId=client_id, groupId=group_id, userId=user_id}"
                    select="FaceDao.getFaceList" />
    </resultMap>

    <select id="queryUserFaceList" resultMap="userFaceResultMap">
        SELECT u.client_id,u.group_id,u.user_id,u.user_info,u.create_time
        FROM tb_user u WHERE u.client_id=#{clientId} AND u.group_id=#{groupId}
    </select>

可以看到在resultMap中有一个collection指向了FaceDao.getFaceList,也就是表示会调用FaceDao.xml中的getFaceList。column指定了查询条件和别名。

FaceDao.xml

<select id="getFaceList" resultType="FaceEntity">
    SELECT u.* FROM tb_face u 
    WHERE u.client_id=#{clientId} AND u.group_id=#{groupId} AND u.user_id=#{userId}
</select>

本博客采用 知识共享署名-禁止演绎 4.0 国际许可协议 进行许可

本文标题:MyBatis一对多关联查询与分步查询

本文地址:https://jizhong.plus/post/2020/04/mybatis-one-to-many.html