1. 程式人生 > >【筆記】Mybatis高階查詢--使用自動對映處理一對一關係

【筆記】Mybatis高階查詢--使用自動對映處理一對一關係

假設在RBAC許可權系統中,一個使用者只能有一個角色,那麼就是一對一關係了。一對一對映因為不需要考慮是否存在重複資料,用起來簡單,所以可以直接使用Mybatis的自動對映。

以下例子為使用自動對映實現在查詢使用者資訊的同時獲取使用者的角色資訊。

  1. 在SysUser類中增加SysRole的屬性,程式碼如下:
    public class SysUser {
        // 其它原有屬性
        
        /**
         * 假設一個使用者只有一個角色(使用自動對映處理一對一關係)
         */
        private SysRole role;
    
        public SysRole getRole() {
    		return role;
    	}
    
    	public void setRole(SysRole role) {
    		this.role = role;
    	}
    }
    
  2. 在對映檔案SysUserMapper.xml增加selectUserAndRoleById方法,如下:
      <!-- 假設一個使用者只有一個角色(使用自動對映處理一對一關係)
      	注意:在查sys_role時列的別名必須要加上"role."字首,通過這種方式將role的屬性對映到SysUser的role屬性上。
      	該字首與SysUser定義的SysRole屬性的欄位、set、get方法字尾要一樣。如定義了SysRole ro,setRo, getRo,
      	那麼sql語句的字首就是ro
       -->
      <select id="selectUserAndRoleById" resultType="ex.mybatis.rbac.model.SysUser">
        select u.id, u.user_name, u.user_password, u.user_email, u.create_time, u.user_info, u.head_img,
        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>
    
  3. 在SysUserMapper介面中增加selectUserAndRoleById方法,如下:
    	/**
         * 假設一個使用者只有一個角色(使用自動對映處理一對一關係)
         * @param id
         * @return
         */
        SysUser selectUserAndRoleById(Long id);
    
  4. 在UserMaperTest類中增加對應的測試方法,如下:
    	@Test
    	public void testSelectUserAndRoleById() {
    		// 獲取SqlSession
    		SqlSession sqlSession = openSession();
    		try {
    			// 獲取SysUserMapper介面
    			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
    			
    			// 呼叫selectUserAndRoleById方法
    			SysUser user = userMapper.selectUserAndRoleById(1001L);
    			
    			// user不為空
    			Assert.assertNotNull(user);
    			
    			System.out.println(user.getRole());
    			
    			// role不為空
    			Assert.assertNotNull(user.getRole());
    			
    			System.out.println();
    		} finally {
    			sqlSession.close();
    		}
    	}
    
  5. 執行結果
    [ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById] - ==>  Preparing: select u.id, u.user_name, u.user_password, u.user_email, u.create_time, u.user_info, u.head_img, 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 = ? 
    [ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById] - ==> Parameters: 1001(Long)
    [ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById] - <==    Columns: id, user_name, user_password, user_email, create_time, user_info, head_img, role.id, role.roleName, role.enabled, role.createBy, role.createTime
    [ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById] - <==        Row: 1001, test, 123456, [email protected], 2018-10-02 17:17:11.0, <<BLOB>>, <<BLOB>>, 2, 普通使用者, 0, 1, 2018-10-01 18:27:37.0
    [ex.mybatis.rbac.mapper.SysUserMapper.selectUserAndRoleById] - <==      Total: 1
    
  6. Mybatis自動對映原理

自動對映是通過別名讓Mybatis自動將值匹配到對應的欄位上,如果是簡單的對映如user_name則對應userName。如果是多層巢狀,如將role.role_name對映到role.roleName上。Mybatis會先查詢role屬性,如果存在就建立role物件,然後在role物件中繼續查詢roleName。將role_name的值繫結到role物件的roleName上。

原始碼處理流程為: 第一步:在org.apache.ibatis.reflection.Reflector的addGetMethods、addSetMethods、addFields方法中把類屬性的欄位名,setter和getter方法進行處理,儲存屬性的型別到一個setTypes和getTypes的map中,key為屬性名或setter、getter後面欄位。如SysUser類經過處理後得到的setTypes和getTypes如下:

setTypes:{userInfo=class java.lang.String, userPassword=class java.lang.String, role=class ex.mybatis.rbac.model.SysRole, headImg=class [B, createTime=class java.util.Date, userEmail=class java.lang.String, id=class java.lang.Long, userName=class java.lang.String}

getTypes:{userInfo=class java.lang.String, userPassword=class java.lang.String, role=class ex.mybatis.rbac.model.SysRole, headImg=class [B, createTime=class java.util.Date, userEmail=class java.lang.String, id=class java.lang.Long, userName=class java.lang.String}

第二步:通過org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings的setValue方法利用反射獲取類的setter方法進行賦值。