MyBatis的使用七(處理表與表之間的關係)

2023-02-04 21:00:33

本文主要講述mybatis的處理表與表之間的關係

一. 介紹t_emp和t_dept表

  1. t_emp表結構

  2. t_dept表結構

二. 資料表的關係

  1. 闡明關係

  一個部門可以有多個員工,但是一個員工只能屬於一個部門

  2. 實體類pojo的宣告

  1) Employee類的宣告如下

public class Employee {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    private Department dept;

    public Employee() {
    }

    get和set()方法...

    @Override
    public String toString() {
        return "Employee{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", dept=" + dept +
                '}';
    }
}

  由於一個員工只能屬於一個部門,因此在Employee中才會有 private Department dept 成員變數。

  2)Department類宣告如下

public class Department {
    private Integer deptId;
    private String deptName;

    private List<Employee> employees;

    public Department() {
    }

    get和set()方法...

    @Override
    public String toString() {
        return "Department{" +
                "deptId=" + deptId +
                ", deptName='" + deptName + '\'' +
                ", employees=" + employees +
                '}';
    }
}

  由於一個部門可以有多個員工,因此在Department類中才會有 private List<Employee> employees 成員變數

三. 使用mybatis解決多對一【一對多】

  1. 多對一的關係

  這裡的多對一的關係是指:多個員工在一個部門,思考的角度是站在員工Employee類的。

  1)提出問題:

  當需要查詢單個員工資訊以及所在部門時,應該如何處理?

  EmpMapper介面宣告如下

public interface EmpMapper {
    // 根據id查詢員工資訊
    Employee selectEmpAndDept(@Param("id") int id);
}

  2)處理方式:

  方式1:採用級聯的方式

  EmpMapper.xml檔案宣告如下

    <!--// 根據id查詢員工資訊
    Employee selectEmpAndDept(@Param("id") int id);-->
    <!--使用: resultType="Employee"結果: Employee{empId=4, empName='趙六', age=24, gender='男', dept=null}-->
    <!--級聯-->
    <resultMap id="resultEmpAndDept1" type="Employee">
        <id column="emp_id" property="empId" />
        <result column="emp_name" property="empName" />
        <result column="dept_id" property="dept.deptId" />
        <result column="dept_name" property="dept.deptName" />
    </resultMap>
    <select id="selectEmpAndDept" resultMap="resultEmpAndDept1">
        SELECT t_emp.*,t_dept.`dept_name`
        FROM t_emp,t_dept
        WHERE t_emp.dept_id = t_dept.dept_id and emp_id = #{id}
    </select>

  前面提過resultMap可以自定義對映名,下面闡述<resultMap>標籤

    <!--
    resultMap:
        id:resultMap標籤的唯一標識
        type:返回型別
        <id>:表t_emp的主鍵的欄位名
        <result>:表t_emp的非主鍵的欄位名
        其中
        <result column="dept_id" property="dept.deptId" />
            column:欄位名dept_id,property:實體類的屬性名dept.deptId
            意義是將查詢到的部門資訊--封裝--》Department物件 --賦值--》Employee類中的dept成員變數
    -->
    <resultMap id="resultEmpAndDept1" type="Employee">
        <id column="emp_id" property="empId" />
        <result column="emp_name" property="empName" />
        <result column="dept_id" property="dept.deptId" />
        <result column="dept_name" property="dept.deptName" />
    </resultMap>        

  注意:<result column="dept_id" property="dept.deptId" />,是Employee類的成員物件dept . 屬性名

  方式2:採用 association 標籤

  EmpMapper.xml檔案宣告如下

    <resultMap id="resultEmpAndDept2" type="Employee">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <!--association的
                     property:是需要處理對映關係的屬性名,如dept
                     javaType:是設定要處理屬性的型別名稱-->
        <association property="dept" javaType="Department">
            <id column="dept_id" property="deptId"></id>
            <id column="dept_name" property="deptName"></id>
        </association>
    </resultMap>
    <select id="selectEmpAndDept" resultMap="resultEmpAndDept2">
        SELECT t_emp.*,t_dept.`dept_name`
        FROM t_emp,t_dept
        WHERE t_emp.dept_id = t_dept.dept_id and emp_id = #{id}
    </select>        

  下面闡述<association>標籤 的內容

   <!--association的
                 property:是需要處理對映關係的屬性名,如dept
                 javaType:是設定要處理屬性的型別名稱-->
    <association property="dept" javaType="Department">
        <id column="dept_id" property="deptId"></id>
        <id column="dept_name" property="deptName"></id>
    </association>    

  方式3:採用分步查詢

  先根據員工編號,查詢員工資訊,在根據員工資訊中的部門編號,查詢相對應的部門資訊

  因此,需要建立DeptMapper介面,DeptMapper介面的宣告如下

public interface DeptMapper {

    // 根據id查詢部門
    Department selectDeptById(@Param("id") int id);
}

  DeptMapper.xml檔案宣告如下

<!--namespace繫結mapper的介面所在的包名.介面名-->
<mapper namespace="com.hspedu.mapper.DeptMapper">
    <!--// 根據id查詢部門
    Department selectDeptById(@Param("id") int id);-->
    <select id="selectDeptById" resultType="Department">
        select * from t_dept where dept_id = #{id}
    </select>

</mapper>

  EmpMapper.xml檔案宣告如下

  <resultMap id="resultEmpAndDept3" type="Employee">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <!--association的
            property:設定需要處理對映關係的屬性的屬性名
            select:設定分步查詢的sql語句的唯一標識
            column:將select標籤中查詢出的某一個欄位作為分步查詢的條件
            fetchType:是否開啟延遲載入【針對某一個sql語句】eager立刻,lazy延遲
            -->
        <association property="dept" fetchType="eager"
                     select="com.hspedu.mapper.DeptMapper.selectDeptById"
                     column="dept_id">
        </association>
    </resultMap>
    <select id="selectEmpAndDeptThree" resultMap="resultEmpAndDept3" >
        select * from t_emp where emp_id = #{id}
    </select>

  下面闡述 <association> 標籤的內容

   <!--association的
          property:設定需要處理對映關係的屬性的屬性名
          select:設定分步查詢的sql語句的唯一標識
          column:將select標籤中查詢出的某一個欄位作為分步查詢的條件
          fetchType:在方法中是否開啟延遲載入【針對某一個sql語句】eager立刻,lazy延遲
    -->
    <association property="dept" fetchType="eager"
                select="com.hspedu.mapper.DeptMapper.selectDeptById"
                column="dept_id">
    </association>

  注意:association標籤中的select的意義,

  在t_emp表中查詢到的員工資訊欄位中的dept_id值作為引數,傳入到DeptMapper介面的selectDeptById()方法中,

  在t_dept表中按照部門編號dept_id查詢相對應的部門資訊。

  分步查詢 插入一個知識點:延遲載入

  a> 引入延遲載入

    當我們只是想查詢員工資訊的姓名時,例如 

    @Test
    // 查詢指定id的員工資訊
    public void test02(){
        Employee employee = mapper.selectEmpAndDept(4);
        System.out.println(employee.getEmpName());
    }

    如果沒有延遲載入的話,執行結果如下

DEBUG 02-04 15:37:05,646 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137) 
DEBUG 02-04 15:37:05,669 ====>  Preparing: select * from t_dept where dept_id = ? (BaseJdbcLogger.java:137) 
DEBUG 02-04 15:37:05,669 ====> Parameters: 100(Integer) (BaseJdbcLogger.java:137) 
DEBUG 02-04 15:37:05,675 <====      Total: 1 (BaseJdbcLogger.java:137) 
DEBUG 02-04 15:37:05,677 <==      Total: 1 (BaseJdbcLogger.java:137) 
趙六

    即執行了查詢員工資訊的sql語句,又執行了查詢部門資訊的sql語句,如何讓它不執行查詢部門資訊的sql語句呢?

  b> 延遲載入的設定

    在mybatis-config.xml檔案中新增如下setting標籤,引入延遲載入

    <settings>
        <!--將MySQL中_對映為java的駝峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
       <!-- 開啟延時載入【懶載入】-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--強制載入所有的懶設定-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    並將<association fetchType="eager"> 的  fetchType = "lazy",即在執行該sql語句時,使用延遲載入,執行結果如下

DEBUG 02-04 15:42:26,231 ==>  Preparing: select * from t_emp where emp_id = ? (BaseJdbcLogger.java:137) 
DEBUG 02-04 15:42:26,261 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137) 
DEBUG 02-04 15:42:26,322 <==      Total: 1 (BaseJdbcLogger.java:137) 
趙六

    只執行了查詢員工資訊的sql語句,說明延遲載入有了效果。

   c> 延遲載入總結:

    引入延遲載入,在mybatis組態檔中新增setting標籤......【全域性 延遲載入】

    如果對於某一個sql語句,不想使用延遲載入,則<association fetchType="eager"> 【區域性 不使用延遲載入】

  3)總結:

  根據傳入的emp_id在t_emp表中查詢員工資訊,員工資訊的欄位中包含有dept_id,然後依據dept_id,在t_dept表中查詢相應的部門資訊,

  將部門資訊--反射-->Department類的物件--賦值-->Employee類的成員變數dept。

  2. 一對多關係

  這裡的一對多是一個部門可以有多個員工,是在Department類角度考慮的。

  1)提出問題

  按照部門編號查詢一個部門有多少員工?

  DeptMapper介面宣告如下

public interface DeptMapper {

    // 查詢一個部門有多少員工
    Department selectDeptAndEmp(@Param("id") int id);
}

  2)處理方式

  方式1:使用collection標籤

  DeptMapper.xml檔案宣告如下

    <!--// 查詢一個部門有多少員工
    Department selectDeptAndEmp(@Param("id") int id);-->
    <resultMap id="resultDeptAndEmp1" type="Department">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="employees" ofType="Employee">
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="age" property="age" ></result>
            <result column="gender" property="gender"></result>
        </collection>
    </resultMap>
    <select id="selectDeptAndEmp" resultMap="resultDeptAndEmp1">
        SELECT t_emp.*,t_dept.*
        FROM t_emp,t_dept
        WHERE t_emp.`dept_id` = t_dept.`dept_id` and t_dept.dept_id = #{id}
    </select>

  下面闡述collection標籤

    <collection property="employees" ofType="Employee">
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="age" property="age" ></result>
            <result column="gender" property="gender"></result>
     </collection>

  property:實體類的成員變數【屬性】,ofType:表示將查詢的結果--封裝-->實體類物件--裝入-->集合

  方式2:分步查詢

  第一步:在t_dept表中根據傳入的dept_id查詢部門資訊

  第二步:在t_emp中根據第一步中得到的dept_id查詢員工資訊

  EmpMapper介面的宣告如下

public interface EmpMapper {

    // 根據部門編號查詢員工資訊
    List<Employee> selectEmployeesByDeptId(@Param("id") int id);
}

  EmpMapper.xml檔案宣告如下

    <!-- // 根據部門編號查詢員工資訊
    List<Employee> selectEmployeesByDeptId(@Param("id") int id);-->
    <resultMap id="resultEmployeesByDeptId" type="Employee">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
    </resultMap>
    <select id="selectEmployeesByDeptId" resultMap="resultEmployeesByDeptId">
        select * from t_emp where dept_id = #{id}
    </select>

  DeptMapper.xml檔案宣告如下

     <resultMap id="resultDeptAndEmp" type="Department">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <association property="employees" fetchType="lazy"
                     select="com.hspedu.mapper.EmpMapper.selectEmployeesByDeptId"
                     column="dept_id"></association>
    </resultMap>
    <select id="selectDeptAndEmpTwo" resultMap="resultDeptAndEmp">
        select * from t_dept where dept_id = #{id}
    </select>

  使用association標籤,

  property:實體類需要對映處理的成員名【屬性】;

  select:呼叫EmpMapper介面的 selectEmployeesByDeptId()方法,即 根據得到的部門資訊中的dept_id,在t_emp表中查詢該部門的所有員工資訊。

  3)總結

  由dept_id在t_emp查詢的結果集--反射-->Employee物件--裝入-->Employee集合--賦值-->Department類的employees成員變數。