mybatis 高级结果映射、一对一、一对多
在关系型数据库中,我们经常要处理一对一、一对多的关系。例如,一辆汽车需要有一个引擎,这是一对一的关系。 一辆汽车有4个或多个轮子,这是一对多的关系。
1.1 一对一映射
1.1.1 使用自动映射处理一对一关系。
/**
* 用户
*/
@Data
public class SysUser {
private String id;
private String userName;
private SysRole role;
}
SysRole.java
/**
* 用户角色
**/
@Data
public class SysRole {
private String id;
private String roleName;
private String userId;
}
使用自动映射就是通过别名让 mabatis 自动将值配到对应的字段上,简单的别名映射如user_name 对应 userName 。除此之外,mabatis 还支持复杂的属性映射,可以多层嵌套,例如将role.role_name 映射到 role.roleName 上。 mabatis 会先查找 role 属性,如果存在role属性就创建 role 对象,然后在 role 对象中继续查找 roleName ,将 role_name 的值绑定到 role 对象的roleName 属性上。
<select id="selectUserAndRoleById" resultType="com.zhang.entity.SysUser">
select u.*,r.*
from `sys_user` u
left join `sys_role` r
on u.`id` = r.`user_id`
where u.id = #{id}
</select>
SysUserMapper.java
/**
* 根据用户 id 获取用户信息和用户的角色信息
* @param id
* @return
*/
SysUser selectUserAndRoleById(String id);
1.2 使用 resultMap 配置一对一映射
除了使用 MyBatis 的自动映射来处理一对一嵌套外,还可以在 XML 映射文件中配置结果
映射。我们使用 resultMap 实现上一节中相同的效果。
<resultMap id="userRoleMap" type="com.zhang.entity.SysUser">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<!-- role 相关属性,role 对应 SysUser.java 中的 role 属性字段-->
<result property="role.id" column="id"/>
<result property="role.userId" column="user_id"/>
<result property="role.roleName" column="role_name"/>
<result property="role.roleId" column="role_id"/>
</resultMap>
这种配置和上一节相似的地方在于, role 中的 property 配置部分使用 “role .” 前缀。colum 部分为了避免不同表中存在相同的列,所有可能重名的列都增加了“ role_ ”前缀。使用这种方式配置的时 候,还需要在查询时设置不同的别名,针对该方法在 serMapper.xml 中增加selectUserAndRoleByid2 方法,代码如下。
<select id="selectUserAndRoleById2" resultMap="userRoleMap">
select
u.id,
u.user_name,
r.role_name,
r.id,
r.role_id,
r.user_id
from `sys_user` u
left join `sys_role` r
on u.`id` = r.`user_id`
where u.id = #{id}
</select>
SysUserMapper.java
/**
* 根据用户 id 获取用户信息和用户的角色信息
* @param id
* @return
*/
SysUser selectUserAndRoleById2(String id);
跟上一个小节不同的是,这里使用的不再是 resultType 了,而是使用 resultMap。 MyBatis 是支持 resultMap 映射继承的,因此要先简化上面的resultMap 配置。例如:
<resultMap id="userRoleMap" type="com.zhang.entity.SysUser" extends="userMap">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<!-- role 相关属性,role 对应 SysUser.java 中的 role 属性字段-->
<result property="role.id" column="id"/>
<result property="role.userId" column="user_id"/>
<result property="role.roleName" column="role_name"/>
<result property="role.roleId" column="role_id"/>
</resultMap>
<resultMap id="userMap" type="com.zhang.entity.SysUser">
</resultMap>
1.3 使用 resultMap 的 association 标签配置一对一映射
在resultMap 中, association 标签用于和一个复杂的类型进行关联,即用于一对一的关联配置。在上面配置的基础上,再做修改,改成 association 标签的配置方式,代码如下。
<resultMap id="userRoleMap" type="com.zhang.entity.SysUser" extends="userMap">
<association property="role" columnPrefix="role_" javaType="com.zhang.entity.SysRole">
<!-- role 相关属性,role 对应 SysUser.java 中的 role 属性字段-->
<result property="id" column="id"/>
<result property="roleName" column="name"/>
<result property="roleId" column="id"/>
<result property="userId" column="user_id"/>
</association>
</resultMap>
<resultMap id="userMap" type="com.zhang.entity.SysUser">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
</resultMap>
association 标签包含以下属性。
property :对应实体类中的属性名,必填项。
javaType :属性对应的 Java 类型。
resultMap :可以直接使用现有的 resultMap 。而不需要在这里配置。
columnPrefix :查询列的前缀,配置前缀后,在子标签配置 result 的 column 可以省略前缀。
2.1 一对多映射
一对多映射只有两种配置方式,都是使用 collection 标签进行的。
2.1.1 collection 集合的嵌套结果映射
与 association 类似,集合的嵌套结果映射就是指通过 SQL 查询将所有的结果查询出来,然后通过配置的结果映射,将数据映射到不同的对象中去。在一对多的关系中, 主表的一条数据会对应关联表中的多条数据,因此一般查询时会查询出多个结果,按照一对多的数据结构存储数据的时候,最终的结果数会小于等于查询的总记录。
系统中, 一个用户拥有多个角色(注意,使用 association 是设定的特例,限制一个用户只有一个角色),每个角色又是多个权限的集合,所以要渐进式地去实现 SQL,查询出所有用户和用户拥有的角色,以及角色所包含的所有权限信息的两层嵌套结果。
先看看一层嵌套的结果,为了能够存储一对多的数据,先对 SysUser 类进行修改:
/**
* 用户
*/
@Data
public class SysUser {
private String id;
private String userName;
/**
* 用户角色集合
* 用于存储用户对应的多个角色
*/
private List<SysRole> roleList;
}
在 SysUserMapperx.xml 中创建 resultMap:
<resultMap id="userRoleListMap" type="com.zhang.entity.SysUser" extends="userMap">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<collection property="roleList" javaType="com.zhang.entity.SysRole">
<id property="id" column="id"/>
<result property="roleId" column="role_id"/>
<result property="userId" column="role_user_id"/>
<result property="roleName" column="role_name"/>
</collection>
</resultMap>
此处就是把 association 改成了 collection,然后将 property 设置为了 roleList ,其他的 id、result 的配置都还一样。仔细想想应该不难理解, collection 用于配置一对多关系,对应的属性必须是对象中的集合类型,因此这里是roleList 。另外, resultMap 只是为了配置数据库宇段和实体属性的映射关系,因此其他都一样。同时能存储一对多的数据结构肯定也能存储一对一关系 ,所以一对 一像是一对多特例, collection 支持的属性以及属性的作用和 association 完全相同 ,这里不做详细介绍。经过简化之后,最终的 userRoleListMap 如下:
<resultMap id="userRoleListMap" type="com.zhang.entity.SysUser" extends="userMap">
<collection property="roleList" resultMap="roleMap"/>
</resultMap>
(待续...)
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)