MyBatis - 3.Mapper XML映射文件


SQL 映射文件有很少的幾個頂級元素(按照它們應該被定義的順序):

  • cache – 給定命名空間的緩存配置。
  • cache-ref – 其他命名空間緩存配置的引用。
  • resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
  • parameterMap – 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除,這里不會記錄。
  • sql – 可被其他語句引用的可重用語句塊。
  • insert – 映射插入語句
  • update – 映射更新語句
  • delete – 映射刪除語句
  • select – 映射查詢語句

1.基本增刪改查

定義接口

public interface employeeMapper {

    public employee getEmployeeById(int id);

    public int addEmp(employee employee);

    public boolean editEmp(employee employee);

    public int delEmp(int id);
}

EmplyoeeMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace:命名空間,指定為接口的全類名
-->
<!--<mapper namespace="com.tancom.tangge.Mapper.employeeMapperpper">-->
<mapper namespace="com.tangge.Mapper.employeeMapper">
  <!--接口方式:
    id:接口方法名 ,resultType:返回類型
  -->
  <select id="getEmployeeById" resultType="com.tangge.model.employee">
    select `id`,  `last_name`  lastName,  `gender`,  `email` from tbl_employee where id = #{id}
  </select>

  <!--插入 parameterType:參數類型(可以省略  -->
  <insert id="addEmp" parameterType="com.tangge.model.employee">
    insert into `db_mybatis`.`tbl_employee` (  `last_name`,  `gender`,  `email`)
        values  (#{lastName},    #{gender},    #{email}  );
  </insert>
  <!--更新-->
  <update id="editEmp">
    update tbl_employee set last_name = #{lastName},email=#{email},gender=#{gender}
    where id =#{id}
  </update>
  <!--刪除-->
  <delete id="delEmp">
    DELETE FROM tbl_employee where id =#{id}
  </delete>
</mapper>

---->【測試】:

/**
     * 1.mybatis 允許直接定義下列返回值
     *   Boolean/Long/Integer
     * 2.手動提交數據
     */
    //插入
    public static void insertTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        //獲取 SqlSession,能直接執行已經映射的SQL語句
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            //employee employee = new employee("jerry","fne@xwf.com",'0');
            employee employee = new employee("lily", "lily@xwf.com", '1');
            //1.插入數據
            int rows = mapper.addEmp(employee);
            System.out.println("影響行數:" + rows);
            //2.手動提交數據
            session.commit();
        } finally {
            session.close();
        }
    }

    //修改
    public static void updateTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        //獲取 SqlSession,能直接執行已經映射的SQL語句
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            employee employee = new employee(4,"jerry","fne@xwf.com",'1');
            //1.修改數據
            boolean rows = mapper.editEmp(employee);
            System.out.println("修改+是否成功:" + rows);
            //2.手動提交數據
            session.commit();
        } finally {
            session.close();
        }
    }
    //刪除
    public static void delTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        //獲取 SqlSession,能直接執行已經映射的SQL語句
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            //1.刪除數據
            int rows = mapper.delEmp(4);
            System.out.println("影響行數:" + rows);
            //2.手動提交數據
            session.commit();
        } finally {
            session.close();
        }
    }

2.獲取自增主鍵值

2.1 有自增功能數據庫(mysql,sqlserver)

Insert, Update, Delete 's Attributes

屬性 描述
useGeneratedKeys (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵
(比如:像 MySQL 和 SQL Server 這樣的關系數據庫管理系統的自動遞增字段),默認值:false。
keyProperty (僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設置它的鍵值,
默認:unset。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。
  <!--
  mybatis獲取自增主鍵,和JDBC一樣,利用statement.getGeneratedKeys()
    - useGeneratedKeys="true" 使用自增主鍵
    - keyProperty:指定對應的主鍵屬性,將這個值賦給 javabean 的哪個屬性
  -->
  <insert id="addEmp" parameterType="com.tangge.model.employee"
    useGeneratedKeys="true" keyProperty="id">
    insert into `db_mybatis`.`tbl_employee` (  `last_name`,  `gender`,  `email`)
        values  (#{lastName},    #{gender},    #{email}  );
  </insert>

---->【測試】:

//插入
    public static void insertTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        //獲取 SqlSession,能直接執行已經映射的SQL語句
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            //employee employee = new employee("jerry","fne@xwf.com",'0');
            employee employee = new employee("lily", "lily@xwf.com", '1');
            //1.插入數據
            int rows = mapper.addEmp(employee);
            System.out.println("影響行數:" + rows);
            System.out.println("添加的員工ID:" + employee.getId());
            //2.手動提交數據
            session.commit();
        } finally {
            session.close();
        }
    }

這里 employee.getId() 獲取值

2.1 沒有自增功能數據庫(oracle)

oracle 不支持自增,使用序列

 <!--oracle插入-->
  <insert id="addEmpByOracle">
    <!--
    keyProperty:查出的主鍵值賦給 javabean 的哪個屬性
    order="BEFORE":當前SQL在插入SQL之前執行
    resultType:返回值類型
    -->
    <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
      <!--查詢主鍵的SQL-->
      SELECT EMPLOYEES_SEQ.nextval FROM dual
    </selectKey>
    <!--oracle主鍵從序列中拿到-->
    insert into employees ( employeeID, `last_name`,  `gender`,  `email`)
        values  (${id}, #{lastName},    #{gender},    #{email}  );
  </insert>

3.參數處理

3.1 單個參數

不做特殊處理。
#{參數}:取出參數值

3.2 多個參數(不推薦)

多個參數會被封裝成一個 map
#{} 就是從map中獲取指定的key。
- key:param1...param2,或有參數的索引也可以
- value:傳入的值

---->【測試】:
新定義一個接口,傳入兩個參數。

public employee getEmployeeParam(int id,String lastName);

以 paramN 傳入key。

	<select id="getEmployeeParam" resultType="com.tangge.model.employee">
    select * from tbl_employee where id = #{param1} and last_name = #{param2}
  </select>

3.3 命名參數(推薦)

明確指定封裝參數時 map 的 key:@Param("id")
多個參數會被封裝為一個 map。
key:使用 @Param 注解指定的值
value:參數值

---->【測試】:

public employee getEmployeeParam(@Param("id") int id,@Param("lastName") String lastName);

@Param 傳入key

<select id="getEmployeeParam" resultType="com.tangge.model.employee">
    <!--select * from tbl_employee where id = #{param1} and last_name = #{param2}-->
     select * from tbl_employee where id = #{id} and last_name = #{lastName}
  </select>

3.4 POJO

如果多個參數正好是我們業務邏輯的數據模型,我們可以直接傳 POJO
#{屬性名}:取出傳入 pojo 的值

3.5 Map

如果多個參數不是我們業務邏輯的數據模型,沒有對應的 POJO,我們也可以傳入Map
#{key}: 取出 map 的值
---->【測試】:

	  <select id="getEmployeeMap" resultType="com.tangge.model.employee">
    select * from tbl_employee where id = #{id} and last_name = #{lastName}
  </select>

定義接口

public interface employeeMapper {
	public employee  getEmployeeMap(Map<String,Object> map);
...
}

測試方法:

    public static void selectMapTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        //獲取 SqlSession,能直接執行已經映射的SQL語句我
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("id", 1);
            map.put("lastName", "tom");
            employee employee = mapper.getEmployeeMap(map);
            System.out.println(employee);
        } finally {
            session.close();
        }
    }

3.6 TO

如果多個參數不是我們業務邏輯的數據模型,又經常要使用,推薦寫一個 TO(Transfer Object)數據傳輸對象

Page{
	int size;
	int index;
}

3.7 List/Collection/Array

把List或數組封裝在Map中
Key:

  • Collection ==> collection
  • List ==> list
  • 數組 ==> array

例子:

public void getEmpId(List<Integer> ids);

取值:第一個id的值:#{list[0]}

3.8 參數值的獲取 (#{}與${}的區別)

#{}:可以獲取map中的值或者pojo對象屬性的值;
${}:可以獲取map中的值或者pojo對象屬性的值;

select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=?
區別:
#{}:是以預編譯的形式,將參數設置到sql語句中;PreparedStatement;防止sql注入
${}:取出的值直接拼裝在sql語句中;會有安全問題;
大多情況下,我們去參數的值都應該去使用#{};

	原生jdbc不支持占位符的地方我們就可以使用${}進行取值
	比如分表、排序。。。;按照年份分表拆分
		select * from ${year}_salary where xxx;
		select * from tbl_employee order by ${f_name} ${order}

---->【測試】:
這里${tableName}是預編譯

<select id="getEmployeeMap" resultType="com.tangge.model.employee">
<!--select * from tbl_employee where id = ? and last_name =?-->
    select * from ${tableName} where id = #{id} and last_name = #{lastName}
  </select>

JAVA

Map<String, Object> map = new HashMap<String, Object>();
            map.put("id", 1);
            map.put("lastName", "tom");
            map.put("tableName", "tbl_employee");
            employee employee = mapper.getEmployeeMap(map);

3.9 #{}:更豐富的用法:

  • 規定參數的一些規則:
    javaType、 jdbcType、 mode(存儲過程)、 numericScale、
    resultMap、 typeHandler、 jdbcTypeName、 expression(未來准備支持的功能);
  • jdbcType 通常需要在某種特定的條件下被設置:
    • 在我們數據為null的時候,有些數據庫可能不能識別mybatis對null的默認處理。比如Oracle(報錯);
      JdbcType OTHER:無效的類型;因為mybatis對所有的null都映射的是原生Jdbc的OTHER類型,oracle不能正確處理;

    • 由於全局配置中:jdbcTypeForNull=OTHER;oracle不支持;兩種辦法
      1、#{email,jdbcType=OTHER};

      insert into employees ( employeeID, `last_name`,  `gender`,  `email`)
      		values  (#{id}, #{lastName},    #{gender},    #{email,jdbcType=NULL}  );
      

      2、jdbcTypeForNull=NULL

      <settings>
        <setting name="jdbcTypeForNull" value="NULL"/>
      </settings>
      

4.Select

4.1 返回 List

接口

public List<employee> getEmployeesByLastNameLike(String lastName);

resultType:如果返回一個集合,只要集合中元素的類型
配置

<!--返回List集合:
      resultType:如果返回一個集合,只要集合中元素的類型
  -->
  <select id="getEmployeesByLastNameLike" resultType="com.tangge.model.employee">
    select * from tbl_employee where  last_name LIKE #{lastName}
  </select>

---->【測試】:

   public static void selectListTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            List<employee> employees = mapper.getEmployeesByLastNameLike("%i%");
            System.out.println(employees);
        } finally {
            session.close();
        }
    }

結果:
[com.tangge.model.employee{id=1, lastName='null', email='tom@guigu.com', gender=0}, com.tangge.model.employee{id=5, lastName='null', email='lily@xwf.com', gender=1}]

4.2 返回 Map

接口

   //返回一條:記錄的map,key 就是列名,value 就是對應的值
    public Map<String,Object> getEmpByIdReturnMap(int id);

    //返回多條:封裝一個Map時,key 是這條記錄的主鍵,value 是記錄封裝后的 javabean
    //@MapKey("last_name") --> key可以得到 last_name 的 字段
    @MapKey("id")
    public Map<Integer,employee> getEmpByLastNameReturnMap(String lastName);

配置
resultType 的 Map 別名 map

  <!--返回一條:Map集合:
      resultType:如果返回一個集合,只要集合中元素的類型
  -->
  <select id="getEmpByIdReturnMap" resultType="map">
    select * from tbl_employee where id = #{id}
  </select>

  <!--返回多條:Map集合:
      resultType:如果返回一個集合,只要集合中元素的類型
  -->
  <select id="getEmpByLastNameReturnMap" resultType="map">
    select * from tbl_employee where last_name LIKE #{lastName}
  </select>

---->【測試】:

    //返回多條 Map
    public static void selectEmpByLastNameReturnMapTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            Map<Integer ,employee> employees = mapper.getEmpByLastNameReturnMap("%i%");
            System.out.println(employees);
            //結果:
            // {1={gender=0, last_name=tomi, id=1, email=tom@guigu.com}, 5={gender=1, last_name=lily, id=5, email=lily@xwf.com}}
        } finally {
            session.close();
        }
    }

    //返回一條Map
    public static void selectEmpByIdReturnMapTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapper mapper = session.getMapper(employeeMapper.class);
            Map<String ,Object> employees = mapper.getEmpByIdReturnMap(1);
            System.out.println(employees);
            //結果:
            //{gender=0, last_name=tomi, id=1, email=tom@guigu.com}
        } finally {
            session.close();
        }
    }

5.resultMap 結果集

resultMap 元素是 MyBatis 中最重要最強大的元素。它可以讓你從 90% 的 JDBC ResultSets 數據提取代碼中解放出來, 並在一些情形下允許你做一些 JDBC 不支持的事情。 實際上,在對復雜語句進行聯合映射的時候,它很可能可以代替數千行的同等功能的代碼。 ResultMap 的設計思想是,簡單的語句不需要明確的結果映射,而復雜一點的語句只需要描述它們的關系就行了。

屬性

  • id 當前命名空間中的一個唯一標識,用於標識一個result map.
  • type 類的完全限定名, 或者一個類型別名 (內置的別名可以參考上面的表格).
  • autoMapping 如果設置這個屬性,MyBatis將會為這個ResultMap開啟或者關閉自動映射。這個屬性會覆蓋全局的屬性 autoMappingBehavior。默認值為:unset。

子屬性

  • constructor - 用於在實例化類時,注入結果到構造方法中
    • idArg - ID 參數;標記出作為 ID 的結果可以幫助提高整體性能
    • arg - 將被注入到構造方法的一個普通結果
  • id – 一個 ID 結果;標記出作為 ID 的結果可以幫助提高整體性能
  • result – 注入到字段或 JavaBean 屬性的普通結果
  • association – 一個復雜類型的關聯;許多結果將包裝成這種類型
    • 嵌套結果映射 – 關聯可以指定為一個 resultMap 元素,或者引用一個
  • collection – 一個復雜類型的集合
    • 嵌套結果映射 – 集合可以指定為一個 resultMap 元素,或者引用一個
  • discriminator – 使用結果值來決定使用哪個 resultMap
    • case – 基於某些值的結果映射
      • 嵌套結果映射 – 一個 case 也是一個映射它本身的結果,因此可以包含很多相 同的元素,或者它可以參照一個外部的 resultMap。

5.1 自定義結果映射規則

定義接口

public interface employeeMapperResultMap {

    public employee getEmployeeById(int id);
}

XML配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tangge.Mapper.employeeMapperResultMap">
  <!--
    resultMap:
    自定義javabean規則,外部 resultMap 的命名引用。結果集的映射是 MyBatis 最強大的特性,對其有一個很好的理解的話,許多復雜映射的情形都能迎刃而解。
    使用 resultMap 或 resultType,但不能同時使用。
     - id:唯一id
     - type:自定義java規則
  -->
  <resultMap id="MyEmp" type="com.tangge.model.employee">
    <!--
    id:指定主鍵封裝規則
      column:指定哪一列,
      property:對應javabean屬性
    -->
    <id column="id" property="id"></id>
    <!--result:其他列的規則-->
    <result column="last_name" property="lastName"></result>
    <result column="email" property="email"></result>
  </resultMap>

  <select id="getEmployeeById"  resultMap="MyEmp">
    select * from tbl_employee where id = #{id}
  </select>
</mapper>

---->【測試】:

public static void selectListTest() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
            employee employees = mapper.getEmployeeById(1);
            System.out.println(employees);
        } finally {
            session.close();
        }
    }

結果:
com.tangge.model.employee{id=1, lastName='tomi', email='tom@guigu.com', gender=0}

5.2 關聯查詢

5.2.1 級聯屬性封裝

tbl_employee 員工表,增加一個字段 dept_id
再增加一個部門表 tbl_dept

public class employee {
    private int id;
    private String lastName;
    private String email;
    private char gender;
    private deptment dept;  //部門
	...
}

部門類

public class deptment {
    private int departmentId;
    private String departmentName;
	...
}

配置 Mapper

<!--1.級聯屬性-->
  <resultMap id="EmpAndDept" type="com.tangge.model.employee">
    <id column="id" property="id"></id>
    <result column="last_name" property="lastName"></result>
    <!--級聯屬性
      deptment:在employee類中定義 privdeptment dept;
    -->
    <result column="dept_id" property="dept.departmentId"></result>
    <result column="dept_name" property="dept.departmentName"></result>
  </resultMap>

  <!--
      查詢結果:
          id  last_name  gender  email  dept_id  dept_name
  -->
  <select id="getEmpAndDept"  resultMap="EmpAndDept">
    SELECT a.*,b.`dept_name` FROM tbl_employee a
    JOIN tbl_dept b
    ON a.dept_id=b.id
    WHERE a.`id`=#{id}
  </select>

---->【測試】:

public static void selectEmpAndDept() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
            employee employees = mapper.getEmpAndDept(1);
            System.out.println(employees);
            /**
             * 結果:
             * employee{id=1, lastName='tomi', email='tom@guigu.com', gender=0,
             * deptment=deptment{departmentId=1, departmentName='技術部'}}
             */
        } finally {
            session.close();
        }
    }

5.2.2 association 嵌套查詢

association + property + javaType
association – 一個復雜類型的關聯;許多結果將包裝成這種類型
Mapper配置

<!--2.association定義聯合對象-->
  <resultMap id="EmpAndDept2" type="com.tangge.model.employee">
    <id column="id" property="id"></id>
    <result column="last_name" property="lastName"></result>
    <!--
      association:指定聯合的對象
        - property="dept":指定哪個屬性是聯合對象
        - javaType:指定類型
    -->
    <association property="dept" javaType="com.tangge.model.deptment">
      <id column="dept_id" property="departmentId"></id>
      <result column="dept_name" property="departmentName"></result>
    </association>
  </resultMap>
  
    <!--
      查詢結果:
          id  last_name  gender  email  dept_id  dept_name
  -->
  <select id="getEmpAndDept"  resultMap="EmpAndDept2">
    SELECT a.*,b.`dept_name` FROM tbl_employee a
    JOIN tbl_dept b
    ON a.dept_id=b.id
    WHERE a.`id`=#{id}
  </select>

結果:
employee{id=1, lastName='tomi', email='null', gender= , dept=deptment{departmentId=1, departmentName='技術部'}}

5.2.3 association 分步查詢

association + select + column

定義部門接口, 獲取部門的方法getDeptbyId

package com.tangge.Mapper;

import com.tangge.model.deptment;

public interface IdeptmentMapper {
        public deptment getDeptbyId(int id);
}

創建XML

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.tangge.Mapper.IdeptmentMapper">

	<select id="getDeptbyId" resultType="com.tangge.model.deptment">
	  select id,dept_name  departmentName from tbl_dept where id = #{id}
	</select>
</mapper>

使用分步查詢

<!--
  3.使用association分步查詢:
    3.1 按照員工id查詢員工信息
    3.2 根據員工的dept_id查詢tbl_dept
    3.3 把部門設置到員工中
-->
  <resultMap id="MyEmpbyStep" type="com.tangge.model.employee">
    <id column="id" property="id"></id>
    <result column="last_name" property="lastName"></result>
    <result column="email" property="email"></result>
    <!--
      association:定義關聯對象的封裝規則
        - select:表名當前屬性調用select指定的方法
        - column:指定講哪一列值傳給方法
    -->
    <association property="dept"
      select="com.tangge.Mapper.IdeptmentMapper.getDeptbyId"
      column="dept_id">
    </association>
  </resultMap>
  <!--getEmpAndDeptByStep-->
  <select id="getEmpAndDeptByStep" resultMap="MyEmpbyStep">
    select * from tbl_employee where id = #{id}
  </select>

---->【測試】:

public static void selectEmpAndDeptStep() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
            employee employees = mapper.getEmpAndDeptByStep(1);
            System.out.println(employees);

        } finally {
            session.close();
        }
    }

這里有個錯誤:蛋疼了1小時
---->【報錯】:

Caused by: java.lang.IllegalArgumentException:
Mapped Statements collection does not contain value for com.tangge.Mapper.IdeptmentMapper.getDeptbyId

為什么TM沒定義。查百度都沒用
后來想起貌似沒有給IdeptmentMapper.xml注冊?????

<mapper resource="com/tangge/Mapper/IdeptmentMapper.xml"/>

ok了。

5.2.4 分步查詢&延遲加載

lazyLoadingEnabled (默認false):延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。 特定關聯關系中可通過設置 fetchType屬性來覆蓋該項的開關狀態。
aggressiveLazyLoading (默認true):當開啟時,任何方法的調用都會加載該對象的所有屬性。否則,每個屬性會按需加載(參考 lazyLoadTriggerMethods).
lazyLoadTriggerMethods :指定哪個對象的方法觸發一次延遲加載。
https://www.cnblogs.com/tangge/p/9518532.html#t1

<settings>
  <!--顯示指定每個我們需要更改的值,即使他是默認的。防止版本更迭帶來的問題-->
  <setting name="lazyLoadingEnabled" value="true" />
  <setting name="aggressiveLazyLoading" value="false" />
  <!--<setting name="mapUnderscoreToCamelCase" value="true"></setting>-->
</settings>

---->【報錯】:

IDEA Cannot enable lazy loading because CGLIB is not available

原因是因為少了cglib.jar,而cglib.jar有引入了asm.jar,所以,這兩個jar包都需要導入。然后再次編譯測試就可以了。

public static void selectEmpAndDeptStep() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
            employee employees = mapper.getEmpAndDeptByStep(1);
//            System.out.println(employees.getEmail());
            System.out.println(employees);
            /**
             * (1)System.out.println(employees.getEmail());
             *  只運行:select * from tbl_employee where id = 1
             *  
             * (2)System.out.println(employees);
             * 同時運行:
             *  1.select * from tbl_employee where id = 1
             *  2.select id,dept_name  departmentName from tbl_dept where id = 1
             */
        } finally {
            session.close();
        }
    }

5.2.5 collection定義關聯集合封裝規則

collection – 一個復雜類型的集合
嵌套結果映射 – 集合可以指定為一個 resultMap 元素,或者引用一個

先新增字段,查詢部門下的所有員工。private List<employee> employees;


public class deptment {

    private int departmentId;
    private String departmentName;
    private List<employee> employees;   //新增:部門下的所有員工

    @Override
    public String toString() {
        return "deptment{" +
                "departmentId=" + departmentId +
                ", departmentName='" + departmentName + '\'' +
                ", employees=" + employees +
                '}';
    }
}

接口

public interface IdeptmentMapper {
        public deptment getDeptbyId(int id);

        //這個,deptment下定義List<employee> 定義collection,
        public deptment getDeptbyIdCollection(int id);
}

定義XML

 <resultMap id="deptCollection" type="com.tangge.model.deptment">
    <id column="dept_id" property="departmentId"></id>
    <result column="dept_name" property="departmentName"></result>
    <!--
      collection定義關聯的集合屬性.
        property:指定變量,這里List<employee> employees
        ofType:指定集合類型
    -->
    <collection property="employees" ofType="com.tangge.model.employee">
      <id column="id" property="id"></id>
      <result column="last_name" property="lastName"></result>
      <result column="email" property="email"></result>
    </collection>
  </resultMap>

  <select id="getDeptbyIdCollection" resultMap="deptCollection">
    SELECT a.*,b.`dept_name` FROM tbl_employee a
      JOIN tbl_dept b
      ON a.dept_id=b.id
      WHERE b.`id`=#{id}
  </select>

---->【測試】:

    public static void selectDeptbyIdCollection() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IdeptmentMapper mapper = session.getMapper(IdeptmentMapper.class);
             deptment deptment = mapper.getDeptbyIdCollection(1);
            System.out.println(deptment);
        } finally {
            session.close();
        }
    }
    /**
     * 結果:
     * deptment{departmentId=1, departmentName='技術部',
     * employees=[employee{id=1, lastName='tomi', email='tom@guigu.com', gender= , dept=null},
     * employee{id=6, lastName='wew', email='wewe@qq.com', gender= , dept=null}]}
     */

5.2.6 collection分步查詢

1.先查部門
2.再查部門下員工

定義部門接口 deptment getDeptbyIdCollectionByStep(int id);

public interface IdeptmentMapper {
        public deptment getDeptbyId(int id);

        //deptment下定義List<employee> 定義collection,
        public deptment getDeptbyIdCollection(int id);

        //分步collection定義:1.先查部門
        public deptment getDeptbyIdCollectionByStep(int id);
}

查詢部門Mapper映射

 <resultMap id="deptCollectionByStep" type="com.tangge.model.deptment">
    <id column="id" property="departmentId"></id>
    <result column="dept_name" property="departmentName"></result>
    <collection property="employees"
      select="com.tangge.Mapper.employeeMapperResultMap.getEmployeesBydeptId"
      column="id">
    </collection>
  </resultMap>
  <!--public deptment getDeptbyIdCollectionByStep(int id);-->
  <select id="getDeptbyIdCollectionByStep" resultMap="deptCollectionByStep">
    select id,dept_name  departmentName from tbl_dept where id = #{id}
  </select>

collection.select 需要員工新增接口List<employee> getEmployeesBydeptId(int id)

public interface employeeMapperResultMap {

    public employee getEmployeeById(int id);

    //聯合查詢
    public employee getEmpAndDept(int id);

    //分步查詢
    public employee getEmpAndDeptByStep(int id);

    //collection:分步查詢2
    public List<employee> getEmployeesBydeptId(int id);
}

員工的Mapper映射

 <!--collection:分步2:再查詢部門下的所有員工-->
  <select id="getEmployeesBydeptId"  resultType="com.tangge.model.employee">
    select * from tbl_employee where dept_id = #{id}
  </select>

---->【測試】:

    public static void selectDeptbyIdCollectionByStep() {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IdeptmentMapper mapper = session.getMapper(IdeptmentMapper.class);
            deptment deptment = mapper.getDeptbyIdCollectionByStep(1);
            System.out.println(deptment);
        } finally {
            session.close();
        }
    }

5.2.7 collection擴展:多列值&fetchType

fetchType:有效值為 lazy(延遲)和eager(立即)。

<resultMap id="deptCollectionByStep" type="com.tangge.model.deptment">
    <id column="id" property="departmentId"></id>
    <result column="dept_name" property="departmentName"></result>
    <!--collection
      - select:表名當前屬性調用select指定的方法
      - column:傳入的值,多值傳輸封裝為Map傳遞:
      {key1=column1,key2=column2,..}
      - fetchType:有效值為 lazy和eager。 如果使用了,它將取代全局配置參數lazyLoadingEnabled。
    -->
    <collection property="employees"
      select="com.tangge.Mapper.employeeMapperResultMap.getEmployeesBydeptId"
      column="{x_deptid=id}" fetchType="lazy">
    </collection>
  </resultMap>

5.2.8 discriminator 鑒別器

(場景需求):
判斷性別:
女生:查部門
男生:lastName 賦值給 email

<!--
  (場景需求):
  判斷性別:
  女生:查部門
  男生:lastName 賦值給 email
  -->
  <resultMap id="MyEmpDis" type="com.tangge.model.employee">
    <id column="id" property="id"></id>
    <result column="last_name" property="lastName"></result>
    <result column="gender" property="gender"></result>
    <!--
      discriminator:
        - column:指定判定的列
        - javaType:列值對應javabean的類型
    -->
    <discriminator javaType="string" column="gender">
      <!--男生 resultType:指定封裝結果類型,不能缺少。 -->
      <case value="0" resultType="com.tangge.model.employee">
        <result column="last_name" property="email"></result>
      </case>
      <!--女生-->
      <case value="1" resultType="com.tangge.model.employee">
        <association property="dept" javaType="com.tangge.model.deptment">
          <id column="dept_id" property="departmentId"></id>
          <result column="dept_name" property="departmentName"></result>
        </association>
      </case>
    </discriminator>
  </resultMap>
  
   <!--getEmpAndDeptByStep-->
  <select id="getEmpAndDeptByStep" resultMap="MyEmpDis">
    select * from tbl_employee where id = #{id}
  </select>

---->【測試】:
如果是女生(id = 5):

employee{id=5, lastName='lily', email='null', gender=1, dept=deptment{departmentId=2, departmentName='null', employees=null}}

如果是男生(id = 1):

employee{id=1, lastName='tomi', email='tomi', gender=0, dept=null}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM