文章目录
1. 高级查询简介
在实际开发过程中,常常要处理关系型数据库中一对一 一对多
的情景,例如:
- 一个汽车有一个引擎(一对一)
- 一个汽车有四个轮子(一对多)
在RABC
系统中还存在一个用户对应多个角色,一个角色有多种权限这样复杂的嵌套关系。
这个时候我们就需要写多个查询方法,然后组合在一起。这样做不仅仅能减少表之间的关联,还使得系统的可拓展性大大提高。
2. 一对一映射
创建数据
假设一个用户只有一种角色,即用户于角色是一对一的关系
@Data
@AllArgsConstructor
@NoArgsConstructor
//用户实体类
public class User {
private Integer id;
private String username;
private String password;
private Role role;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
//角色类
public class Role {
private Integer id;
private String role;
private Date createDate;
}
2.1 关联的嵌套结果映射
2.1.1 使用自动映射处理一对一关系
使用自动映射就是让MyBatis将值自动匹配到对应的字段上
。例如:
user_name
匹配到userName
role.role_name
匹配到role.roleName
(这属于复杂嵌套
,MyBatis会先查找role
属性,如果存在role
属性就创建role
对象,然后再从对象中查找roleName
属性,最后将role_name
的值绑定到上面)
UserMapper.xml
中的方法:
<select id="selectUserAndRoleById" resultType="com.example.pojo.User">
select user.id, username, password, r.id "role.id", r.role "role.role", r.create_date "role.createDate"
from user
inner join user_role_merage urm on user.id = urm.user_id
inner join role r on urm.role_id = r.id
where user.id = #{id}
</select>
注意:上面role表的查询的列的名都有"role.
"前缀,通过这种方式可以将值绑定到user
中的role
属性上
测试成功
- 像这种通过一次查询将结果映射到不同对象的方式,称之为关联的嵌套结果查询。
- 关联的嵌套结果查询需要关联多张表一次性将所需要的数据全部查询出来。
- 关联的嵌套结果的查询的好处是:减少数据库查询次数,减轻数据库压力;缺点是:需要写出比较复杂的SQL
2.1.2 使用resultMap配置一对一映射
使用resultMap
配置可以实现与2.1 使用自动映射处理一对一关系
相同的结果。
<resultMap id="userRoleMap" type="com.example.pojo.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="role.id" column="role_id"/>
<result property="role.role" column="role_role"/>
<result property="role.createDate" column="role_create_date"/>
</resultMap>
<select id="selectUserAndRoleById" resultMap="userRoleMap">
select user.id, username, password, r.id "role_id", r.role "role_role", r.create_date "role_create_date"
from user
inner join user_role_merage urm on user.id = urm.user_id
inner join role r on urm.role_id = r.id
where user.id = #{id}
</select>
使用resultMap
这种配置与自动映射完成一对一关系
中相似的地方是:property配置部分都使用了role.
前缀。
测试成功:
与上一种方法相比,resultMap
的方法非常繁琐,甚至增加了更多的工作量。MyBatis是支持resultMap继承的
,因此要简化上面的写法。
<resultMap id="userMap" type="com.example.pojo.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
</resultMap>
<!--userRoleMap只需要继承userMap并且添加role特有的配置即可-->
<resultMap id="userRoleMap" extends="userMap" type="com.example.pojo.User">
<result property="role.id" column="role_id"/>
<result property="role.role" column="role_role"/>
<result property="role.createDate" column="role_create_date"/>
</resultMap>
使用简化后的resultMap配置一对一映射仍然不算方便,至少没有那么麻烦
2.1.3 使用resultMap的association标签配置一对一映射
association
标签用于和一个复杂类型相关联,即用于一对一的关联配置。
对上面的代码进行修改:
<resultMap id="userRoleMap" extends="userMap" type="com.example.pojo.User">
<association property="role" javaType="com.example.pojo.Role"
columnPrefix="role_">
<result property="id" column="id"/>
<result property="role" column="role"/>
<result property="createDate" column="create_date"/>
</association>
</resultMap>
- 在
association
中配置了role
,所以在result中的property
中就按属性名写; columnPrefix
设置了字段前缀,MyBatis会根据字段前缀+column去匹配查询出的字段;
使用association
配置时还可以使用resultMap
属性来配置一个现成的resultMap
映射。
<resultMap id="userRoleMap" extends="userMap" type="com.example.pojo.User">
<association property="role" javaType="com.example.pojo.Role"
columnPrefix="role_" resultMap="com.example.mapper.RoleMapper.roleMapper">
</association>
</resultMap>
RoleMapper.xml
中
<resultMap id="roleMapper" type="com.example.pojo.Role">
<id property="id" column="id"/>
<result property="role" column="role"/>
<result property="createDate" column="create_date"/>
</resultMap>
这种方法是比较简单的,原因之一就是MyBatis可以自动生成resultMap
。
以上的三种方法都属于“关联的嵌套结果映射”,意思就是通过一次查询将不同的属性值映射到不同的对象中。还有一种:关联的嵌套查询,言外之意就是有额外的查询。
2.2 关联的嵌套查询
2.2.1 association标签的嵌套查询
除了使用关联的嵌套结果映射
,我们还可以利用简单的SQL通过多次查询来获得我们的结果,这种方法和在逻辑层手动执行多次SQL的方式很像,最后会将结果组合成一个对象
association
嵌套查询常用的属性如下:
select
:另一个映射查询的id,MyBatis会额外执行这个查询获取嵌套对象的结果。column
:将主查询中列的结果作为嵌套查询的参数,配置方式:column={prop1=col1,prop2=col2}
,其中,prop1和prop2为参数。fetchType
:加载方式:lazy或者eager
代码如下:
<resultMap id="userRoleMap" extends="userMap" type="com.example.pojo.User">
<association property="role" select="com.example.mapper.RoleMapper.selectRoleById" column="{id=role_id}"/>
</resultMap>
<select id="selectUserAndRoleById" resultMap="userRoleMap">
select user.id, username, password ,urm.role_id
from user
inner join user_role_merage urm on user.id = urm.user_id
where user.id = #{id}
</select>
RoleMapp.xml
<select id="selectRoleById" resultType="com.example.pojo.Role">
select * from role where id = #{id}
</select>