1. 程式人生 > >《Mybatis從入門到精通》讀書筆記(三)

《Mybatis從入門到精通》讀書筆記(三)

第六章. Mybatis高階查詢

在關係型資料庫中,我們經常要處理一對一,一對多的關係。在面對這種關係的時候,我們可能要寫多個方法分別查詢這些資料,然後再組合到一起。這種處理方式特別適合用在大型系統上,由於分庫分表,這種用法可以減少表之間的關聯查詢,方便系統進行擴充套件。但是在一般的企業應用中,使用Mybatis的高階結果對映便可以輕鬆地處理這種一對一、一對多的關係。

6.1. 高階結果對映

6.1.1. 一對一對映

1. 使用自動對映處理一對一關係

使用自動對映就是通過別名讓Mybatis自動將值匹配到對應的欄位上,簡單的別名對映如user_name對應userName。除此之外Mybatis還支援複雜的屬性對映,可以多層巢狀,例如將role.role_name對映到role.roleName上。Mybatis會先查詢role屬性,如果存在role屬性就建立role物件,然後在role物件中繼續查詢roleName,將role_name的值繫結到role物件的roleName屬性上。

<select id="selectUserAndRoleById" resultType="tk.mybatis.simple.model.SysUser">
	select 
	   	u.id, 
	   	u.user_name userName, 
	    u.user_password userPassword,
	    u.user_email userEmail,
	    u.user_info userInfo,
	    u.head_img headImg,
	    u.create_time createTime,
		r.id "role.id", 
		r.role_name "role.roleName", 
		r.enabled "role.enabled",
		r.create_by "role.createBy",
		r.create_time "role.createTime"
	from sys_user u
	inner join sys_user_role ur on u.id = ur.user_id
	inner join sys_role r on ur.role_id = r.id
	where u.id = #{id}
</select>

注意上述方法中sys_role查詢列的別名都是“role.”字首,通過這種方式將role的屬性都對映到了SysUser的role屬性上。

2. 使用resultMap的association標籤配置一對一對映

<!-- <cache-ref namespace="tk.mybatis.simple.mapper.RoleMapper"/> -->
<resultMap id="userMap" type="tk.mybatis.simple.model.SysUser">
	<id property="id" column="id"/>
	<result property="userName" column="user_name"/>
	<result property="userPassword" column="user_password"/>
	<result property="userEmail" column="user_email"/>
	<result property="userInfo" column="user_info"/>
	<result property="headImg" column="head_img" jdbcType="BLOB"/>
	<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>
<resultMap id="userRoleMap" extends="userMap" type="tk.mybatis.simple.model.SysUser">
	<!-- 2. 直接引用RoleMapper裡的resultMap -->
	<association property="role" columnPrefix="role_" resultMap="tk.mybatis.simple.mapper.RoleMapper.roleMap"/>
	<!-- 1. 直接羅列出來sys_role表字段和SysRole屬性的對映關係 -->
	<!--<association property="role" columnPrefix="role_" javaType="tk.mybatis.simple.model.SysRole">
			<id property="id" column="id"/>
			<result property="roleName" column="role_name"/>
			<result property="enabled" column="enabled"/>
			<result property="createBy" column="create_by"/>
			<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
	</association>-->
</resultMap>
<mapper namespace="tk.mybatis.simple.mapper.RoleMapper">

	<resultMap id="roleMap" type="tk.mybatis.simple.model.SysRole">
		<id property="id" column="id"/>
		<result property="roleName" column="role_name"/>
		<result property="enabled" column="enabled"/>
		<result property="createBy" column="create_by"/>
		<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
	</resultMap>
</mapper>

association標籤包含包含以下屬性:

  • property:對應實體類中的屬性名,必填項
  • javaType:屬性對應的Java型別
  • resultMap:可以直接使用現有的resultMap,而不需要在這裡配置
  • columnPrefix:查詢列的字首,配置字首後,在子標籤配置result的column時可以省略字首

3. association標籤的巢狀查詢

上面介紹的都屬於巢狀的結果對映,需要關聯多個表將所有需要的值一次性查詢出來。這種方式的好處是減少資料庫查詢次數,減輕資料庫的壓力,缺點是要寫很複雜的SQL,並且當巢狀結果更復雜時,不容易一次寫正確,由於要在應用伺服器上將結果對映到不同的類上,因此也會增加應用伺服器的壓力。當一次會使用到巢狀結果,並且整個複雜的SQL執行速度很快時,建議使用關聯的巢狀結果對映。

除了這兩種通過複雜的SQL查詢獲取結果,還可以利用簡單的SQL通過多次查詢轉化為我們需要的結果,這種方式與根據業務邏輯手動執行多次SQL的方式很像,最後會將結果組合成一個物件。

association標籤的巢狀查詢常用的屬性如下:

  • select:另一個對映查詢的id,Mybatis會額外執行這個查詢獲取巢狀物件的結果。
  • column:列名(別名)將住查詢中列的結果作為巢狀查詢的引數,配置方式如column={prop1=col1,prop2=col2},prop1和prop2將作為巢狀查詢的引數。
  • fetchType:資料載入方式,可選值為lazyeager,分別為延遲載入和積極載入,這個配置會覆蓋全域性的lazyLoadingEnabled配置

UserMapper.xml配置:

<resultMap id="userRoleMapSelect" extends="userMap" type="tk.mybatis.simple.model.SysUser">
	<association property="role" 
				 fetchType="lazy"
				 select="tk.mybatis.simple.mapper.RoleMapper.selectRoleById" 
				 column="{id=role_id}"/>
</resultMap>

<select id="selectUserAndRoleByIdSelect" resultMap="userRoleMapSelect">
    select 
    	u.id, 
    	u.user_name, 
        u.user_password,
        u.user_email,
        u.user_info,
        u.head_img,
        u.create_time,
	    ur.role_id
	from sys_user u
	inner join sys_user_role ur on u.id = ur.user_id
    where u.id = #{id}
</select>

RoleMapper.xml配置:

<select id="selectRoleById" resultMap="roleMap">
	select * from sys_role where id = #{id}
</select>

3.1. 實現延遲載入

lazyLoadingEnabled 延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入。 特定關聯關係中可通過設定fetchType屬性來覆蓋該項的開關狀態。 true | false false
aggressiveLazyLoading 當開啟時,任何方法的呼叫都會載入該物件的所有屬性。當關閉時,每個屬性會按需載入(參考lazyLoadTriggerMethods). true | false false (true in ≤3.4.1)
lazyLoadTriggerMethods 指定哪個物件的方法觸發一次延遲載入。 用逗號分隔的方法列表。 equals,clone,hashCode,toString

首先全域性mybatis-config.xml關閉aggressiveLazyLoading:

<settings>
    <!-- 其他配置 -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

其次在

<resultMap id="userRoleMapSelect" extends="userMap" type="tk.mybatis.simple.model.SysUser">
	<association property="role" 
				 fetchType="lazy"
				 select="tk.mybatis.simple.mapper.RoleMapper.selectRoleById" 
				 column="{id=role_id}"/>
</resultMap>