MyBatis加強(1)~myBatis物件關係對映(多對一關係、一對多關係)、延遲/懶載入

一樂樂發表於2022-02-06

一、myBatis物件關係對映(多對一關係、一對多關係)

1、多對一關係:

---例子:多個員工同屬於一個部門。


(1)myBatis傳送 額外SQL:

■ 案例:員工表通過 dept_id 關聯 部門表,需求:查詢指定員工id、name、所屬的部門名稱的資訊。

image

//部門物件的介面、對映檔案省略,跟員工邏輯差不多

/* 員工物件的介面 */
public interface EmployeeMapper {
	Employee get(Long id);
}
	
<!--員工物件的對映檔案-->
<!-- 解決列名和屬性名不匹配問題 -->
<resultMap  id="BaseResultMap" type="Employee">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<result column="dept_id" property="dept.id"/> 		
</resultMap>

<!-- 查詢操作 -->
<select id="get" resultMap="BaseResultMap">
    select id, name, dept_id from employee2 where id = #{id}
</select>


/* 測試:查詢指定員工id、name、所屬的部門名稱的資訊 */
	@Test
	public void testGet() throws Exception {	
		SqlSession session = MyBatisUtil.getSession();	
		EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
		Employee e = employeeMapper.get(1L);
		System.out.println(e);
		//需要通過查詢得到的dept_id查詢獲取得到部門物件
		/**
		 * 額外的查詢語句,可以通過配置resultMap的association屬性,讓myBatis幫我們執行
		 */
		//手動新增額外查詢語句
//		Long dept_id = e.getDept().getId();
//		DepartmentMapper departmentMapper = session.getMapper(DepartmentMapper.class);
//		Department d = departmentMapper.get(dept_id);
//		e.setDept(d);
		

		System.out.println(e.getDept());	
		session.commit();
		session.close();
	}
  • 上面是通過手動新增的額外SQL查詢,通過配置resultMap的association屬性,讓myBatis幫我們執行如下:

	<!-- 解決列名和屬性名不匹配問題 -->
	<resultMap  id="BaseResultMap" type="Employee">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!--<result column="dept_id" property="dept.id"/> -->
		<!-- 額外的SQL配置方式
			association元素:配置單一元素的關聯關係
			property 屬性:物件的屬性
			select 屬性:傳送額外的sql
			column 屬性: 將指定的列的值傳遞給額外sql
		 -->
		<association property="dept"
			 select="com.shan.hello.mappe r.DepartmentMapper.get"
              column="dept_id" 
			 />
			
	</resultMap>

(2)使用額外的 SQL 做對映配置會導致的問題:N+1問題

例如:每個員工的部門編號dept_id 是不同的,當查詢所有員工的id、name、所屬的部門名稱的資訊時就會傳送額外N條SQL語句。

  • N:傳送額外N條SQL語句去查詢員工所屬的部門名稱: select name from department where id = dept_id;

  • 1:查詢所有員工的id、name、所屬的部門的編號dept_id:select * from employee;

----解決:使用內聯對映(多表查詢),此時一條 SQL 語句搞定。

----處理多表查詢的結果集的方法:內聯對映


(3)物件關聯的查詢:

方式一:額外的SQL

方式二:內聯對映


(4)處理多表查詢的結果集的方法【內聯對映】:

  • 方式一:屬性名-列名 通過resultMap的子元素result進行對映配置[內聯對映-使用result]:

image


  • 方式二:屬性名-列名 通過resultMap的子元素association進行對映配置[內聯對映-使用association]

image


(5)多對一關係配置總結:

使用association元素,配置單一物件屬性。

  • 方式一:額外的SQL[分步查詢],一般需要進入另外一個頁面展示更加詳細的資訊。
  • 方式二:內聯對映[多表查詢],常用。需要在列表中顯示關聯物件的資料,使用內聯對映,否則會出現N+1問題。



2、一對多關係配置:

---例子:一個部門有多個員工。


(1)一對多關係-額外的SQL:

<!-- 針對單一物件的屬性,使用association元素 -->
<!-- 針對集合型別的屬性,使用collection元素 -->  
<!-- 額外的SQL配置方式
	collection元素:配置集合型別元素的關聯關係
	property 屬性:物件的屬性
	select 屬性:傳送額外的sql
	column 屬性: 將指定的列的值傳遞給額外sql
-->

<resultMap id="BaseResultMap" type="Department">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!--<result column="" property="emps"/> -->
	<collection property="emps"
		select="com.shan.hello.mapper.EmployeeMapper.get"
	 	column="id" >
	 </collection>
</resultMap>


<select id="get" resultMap="BaseResultMap">
	 select id, name from department where id = #{id}  
</select>

(2)一對多關係-內聯查詢:

<!-- 針對單一物件的屬性,使用association元素 -->
<!-- 針對集合型別的屬性,使用collection元素 --> 
<resultMap id="BaseResultMap" type="Department">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!--<result column="" property="emps"/> -->
	<!-- 
		內聯查詢:ofType是集合中泛型的型別
	 --> 
	<collection property="emps" ofType="Employee">
		<result column="e_id" property="id"/>
		<result column="e_name" property="name"/>
		<result column="e_dept_id" property="deptId"/>
	</collection>
</resultMap>


<select id="get" resultMap="BaseResultMap">
	 <!-- select id, name from department where id = #{id}  --> 
     select d.id, d.name, e.id e_id, e.name e_name, e.dept_id e_dept_id from department d
  	 join employee2 e on d.id = e.dept_id where d.id = #{id}	
</select>



二、設定延遲/懶載入

  	<!-- 全域性配置檔案 -->
  	<settings>
  		<!-- 懶載入/延遲載入,開啟延遲載入功能 -->
  		<setting name="lazyLoadingEnabled" value="true"/>
  		<!-- 設定不要積極地去查詢關聯物件 -->
  		<setting name="aggressiveLazyLoading" value="false"/>
         <!-- 延遲載入的觸發方法 -->
  		<setting name="lazyLoadTriggerMethods" value="close"/>
  	</settings>
  • 動態代理-增強功能--延遲載入



總結:多對一、一對多關係的單屬性物件/集合屬性物件,使用association或collection元素?使用額外SQL或內聯查詢?

  • 針對【單屬性物件】:使用assoication元素,通常需要使用多表查詢操作,即內聯查詢

  • 針對【集合屬性物件】:使用collection元素,通常還要使用延遲載入,即額外SQL處理

相關文章