Mybatis一对一、一对多查询

2,061 阅读1分钟

一、一对一

一般一对一使用 <association> 标签 <association>标签的常用属性如下:

  • property:返回类型参数,一般为实体类的变量名一样即可
  • select:另一个映射查询的 id, MyBatis 会额外执行这个查询获取嵌套对象的结果
  • column:列名(或者别名),将主查询中列的结果作为嵌套查询的参数,配置方式如下 column={propl=coll , prop2=col2}, propl 和 prop2 将作为嵌套查询的参数。
  • fetchType:数据加载方式,可选值为 lazy 和 eager,分别为延迟加载和积极加载

创建2张实体表

// 员工表
public class Employee {
    private Integer id;
    private String lastName;
    private String gender;
    private String email;
    private Department dept; //一对一,一个员工对应一个公司
}
// 公司表
public class Department {
    private Integer id;
    private String departmentName;
}
  1. 使用查询2张表关联对象映射方式
<resultMap type="com.mybatis.domain.Employee" id="myEmp">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
    <!-- 关联对象 -->
    <association property="dept" javaType="com.mybatis.domain.Department">
        <!-- 关联条件Employee的dept_id对应着Department的id -->
        <id column="dept_id" property="id"/>
        <result column="department_name" property="departmentName"/>
    </association>
</resultMap>

<!-- resultMap指定使用上面定义的结果集,查询使用关联查询,查询列要和上面的column对应 -->
<select id="getEmpAndDeptById" resultMap="myEmp">
    select e.id,e.last_name,e.gender,e.email,e.dept_id,d.id,d.department_name
     from tbl_employee e,tbl_department d
     where e.dept_id = d.id and e.id=#{id}
</select>
  1. 使用嵌套查询方式,则子查询依赖上一级查询返回的结果
// 对应DepartmentMapper
<select id="getDeptById" resultType="com.mybatis.domain.Department">
        select * from tbl_department
        where id = #{id}
</select>

// 对应EmployeeMapper
<mapper namespace="com.mybatis.mapper.EmployeeMapperPlus">
    <resultMap type="com.mybatis.domain.Employee" id="myEmpByStep">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        <!-- 使用select属性指定第二步调用的方法,并通过column指定传递的参数值,这个值是第一步的查询的数据 -->
        <association property="dept" 
            select="com.mybatis.mapper.DepartmentMapper.getDeptById"
            column="dept_id">
        </association>
    </resultMap>
    
    <!-- 第一步值只查询tbl_employee表 -->
    <select id="getEmpAndDeptByStep" resultMap="myEmpByStep">
        select id,last_name,gender,email,dept_id
         from tbl_employee
         where id = #{id}
    </select>
</mapper>

二、一对多

使用<collection >标签,有两种使用方式

  1. 代码复用性高, 主表分页查询正确(嵌套查询) QuestionMapper.xml
<mapper namespace="com.xxx.modules.xxx.mapper.QuestionMapper">

<resultMap id="BaseResultMap" type="com.xxx.modules.xxx.entity.Question" >
    <id column="id" 		 property="id"      jdbcType="VARCHAR" />
    <result column="content" property="content" jdbcType="VARCHAR" />
    <result column="type"    property="type"    jdbcType="VARCHAR" />
    <result column="sort"    property="sort"    jdbcType="INTEGER" />
    <collection property="options" javaType="java.util.ArrayList" 
      ofType="com.xxx.modules.xxx.entity.QuestionOption"
      select="com.xxx.modules.xxx.mapper.QuestionOptionMapper.selectList" 
      column="{qid=id,sort=sort}" />
    
      <!-- qid/sort是定义的变量名, id/sort是主表的字段id/sort,
	   先查出主表的结果, 然后主表记录数是几 就执行几次 collection 的select,
	   javaType和ofType 写不写都行,
	   select的值: 对应xml的namespace + 对应xml中的代码片段的id,
	   column作为select语句的参数传入,如果只传一个参数id可以简写: column="id" 
     -->
</resultMap>

<!-- 查询列表 -->
<select id="selectList" resultMap="BaseResultMap">
    SELECT pq.id, pq.content, pq.type, pq.sort
    FROM question AS pq
</select>

QuestionOptionMapper.xml

<mapper namespace="com.xxx.modules.xxx.mapper.QuestionOptionMapper">

 <!-- 查询列表 -->
 <select id="selectList" resultType="QuestionOption">
     SELECT
     	pqo.id, pqo.content, pqo.sort
     FROM
     	question_option AS pqo
     <where>
     	pqo.qid = #{qid} <!-- 变量名 qid 对应上文的 qid -->
     	<!-- 如果上文中 collection只传一个参数column="id",只要类型匹配,在这里随便写个变量名就可		  以取到值 #{xyz} -->
     </where>
 </select>
  1. 只需要执行一次sql查询, 主表分页查询不正确(联表查询) QuestionMapper.xml
<mapper namespace="com.xxx.modules.xxx.mapper.QuestionMapper">

<resultMap id="BaseResultMap" type="com.xxx.modules.xxx.entity.Question" >
    <id column="id" 		 property="id"      jdbcType="VARCHAR" />
    <result column="content" property="content" jdbcType="VARCHAR" />
    <result column="type"    property="type"    jdbcType="VARCHAR" />
    <result column="sort"    property="sort"    jdbcType="INTEGER" />
    <collection property="options" javaType="java.util.ArrayList" ofType="com.xxx.modules.data.entity.QuestionOption">
        <id column="o_id" property="id" jdbcType="VARCHAR" />
        <result column="o_content" property="content" jdbcType="VARCHAR" />
        <result column="o_sort" property="sort" jdbcType="INTEGER" />
    </collection>
        <!-- 列的别名 o_id,o_content,o_sort , 起别名是因为主子表都有这几个字段
                 这里要写 ofType, javaType还是可以不写 -->
</resultMap>

<!-- 查询列表 -->
<select id="selectList" resultMap="BaseResultMap">
    SELECT
        pq.id, pq.content, pq.type, pq.sort
        ,pqo.id AS oid ,pqo.content AS ocontent ,pqo.sort AS osort 
        <!-- 联查子表字段,起别名 -->
    FROM
        question AS pq
        LEFT JOIN question_option pqo ON pq.id = pqo.qid <!-- 联查子表 -->
    <where>  
    </where>
</select>