Result Map

constructor

    <resultMap id="UserBasic" type="com.alibaba.force.dal.model.capsulation.UserBasic">
        <constructor>
            <arg column="u_name" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="u_username" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="u_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
            <arg column="u_state" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="u_avatar" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="u_extern_uid" jdbcType="VARCHAR" javaType="java.lang.String"/>
        </constructor>
    </resultMap>

@ToString
@Getter
@Setter
public class UserBasic extends UserSafe {
    private Long id;

    private String state;

    @JSONField(name = "avatar_url")
    private String avatarUrl;

    @JSONField(name = "extern_uid")
    private String externUid;

    /**
     * @param name
     * @param username
     * @param id
     * @param state
     * @param avatar    注意,这里需要做一些额外操作
     * @param externUid
     */
    public UserBasic(String name, String username, Long id, String state, String avatar, String externUid) {
        super(name, username);
        this.id = id;
        this.state = state;
        this.externUid = externUid;
        this.setAvatarUrl(UsersUtil.getAvatarUrl(UsersBuilder.newBuilder().setId(id).setAvatar(avatar)
            .setExternUid(externUid).build()));
    }

    public UserBasic() {
    }

    @Override
    public UserBasic merge(@NonNull Users users) {
        super.merge(users);
        this.setId(users.getId());
        this.setState(users.getState());
        this.setAvatarUrl(UsersUtil.getAvatarUrl(users));
        this.setExternUid(users.getExternUid());
        return this;
    }
}

注意入参的顺序保持一致

association

association字段可以直接增加ResultMap的子属性。

    <resultMap id="MigrateTaskRecordDO" type="com.alibaba.force.dal.model.capsulation.MigrateTaskRecordDO">
  <id column="id" jdbcType="BIGINT" property="id" />
  <id column="u_id"/>
  <result column="gmt_create" jdbcType="TIMESTAMP" property="gmtCreate" />
  <result column="gmt_modified" jdbcType="TIMESTAMP" property="gmtModified" />
  <association property="creator" javaType**="com.alibaba.force.dal.model.capsulation.UserBasic"    resultMap="UserBasic"/>
</resultMap>

association中的resultMap所指向的字段也必须是申明过的ResultMap对象。
result需要放置在association之前。

N+1问题

注意上面例子中的多个标签

有这么一个场景,会产生坑:
当查询1对多的关系时,如果采用了嵌套的方式(association、collection),则MyBatis会在DefaultResultSetHandler中调用handleRowValuesForNestedResultMap
方法。
该方法采用了计算key(createRowKey)的方式来记录已经遍历过的对象,并且下次从缓存中拿(减少内存的消耗,共享嵌套的重复对象)。

而由于N+1的select一定是根据这个“1”去查询其他的“N”的,如果此时<id>不变,为主键,那么就会被丢弃很多结果(理论上不重复,但是由于上述的计算规则,被MyBatis认为是重复)。因此,使用多个联合字段作为id是最棒的解。这些联合ID需要是最终确定一个不重复对象的唯一值。

MyBatis版本:3.4.4