日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】

發(fā)布時間:2025/3/21 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 概述
  • 需求
  • 方式一:使用自動映射處理一對一映射
    • 實體類改造
    • UserMapper接口增加接口方法
    • UserMapper.xml增加SQL
    • 單元測試
  • 方式二:使用resultMap配置一對一映射
    • UserMapper接口增加接口方法
    • UserMapper.xml增加SQL
    • 單元測試
  • 方式三:使用resultMap的asscociation標簽配置一對一映射
    • UserMapper接口增加接口方法
    • UserMapper.xml增加SQL
    • 單元測試
  • 方式四:asscociation標簽的嵌套查詢

概述

我們還是繼續(xù)使用我們的RBAC權(quán)限系統(tǒng)來演示。

假設(shè)在RBAC權(quán)限系統(tǒng)中,一個用戶只能擁有一個角色。


需求

實現(xiàn)在查詢用戶信息的同時獲取用戶擁有的角色信息


方式一:使用自動映射處理一對一映射

實體類改造

一個用戶擁有一個角色,因此現(xiàn)在SysUser類中增加SysRole字段

/*** * * @ClassName: SysUser* * @Description: 用戶表* * @author: Mr.Yang* * @date: 2018年4月13日 下午9:24:21*/ public class SysUser {//其他原有字段以及setter getter/*** 用戶角色*/private SysRole sysRole;// setter getterpublic SysRole getSysRole() {return sysRole;}public void setSysRole(SysRole sysRole) {this.sysRole = sysRole;}}

使用自動映射就是通過別名讓MyBatis自動將值匹配到對應的子彈上,簡單的別名映射如user_name 對應userName .

除此之外MyBatis還支持復雜的屬性映射,可以多層嵌套。 比如將role.role_name 映射到 role.roleName上。 MyBatis首先會查找role屬性,如果存在role屬性就創(chuàng)建role對象,然后在role對象中繼續(xù)查找roleName, 將role_name的值綁定到role對象的roleName屬性上 。


UserMapper接口增加接口方法

/*** * * @Title: selectSysUserAndSysRoleById* * @Description: 根據(jù)Id查詢用戶信息的同時獲取用戶擁有的角色信息* * @param id* @return* * @return: SysUser*/SysUser selectSysUserAndSysRoleById(Long id);

UserMapper.xml增加SQL

<select id="selectSysUserAndSysRoleById" resultType="com.artisan.mybatis.xml.domain.SysUser">SELECTu.id,u.user_name userName,u.user_password userPassword,u.user_email userEmail,u.user_info userInfo,u.create_time createTime,u.head_img headImg,r.id "sysRole.id",r.role_name "sysRole.roleName",r.enabled "sysRole.enabled",r.create_by "sysRole.createBy",r.create_time "sysRole.createTime"FROMsys_user uINNER JOIN sys_user_role ur ON u.id = ur.user_idINNER JOIN sys_role r ON ur.role_id = r.idWHEREu.id = #{id}</select>

注意上述SQL中 sys_role查詢的列的別名都是 “sysRole.”前綴,這和SysUser實體類中SysRole屬性的名稱保持一致,通過這種方式將sysRole的屬性都映射到了SysUser的sysRole屬性上


單元測試

@Testpublic void selectSysUserAndSysRoleByIdTest() {logger.info("selectSysUserAndSysRoleByIdTest");// 獲取SqlSessionSqlSession sqlSession = getSqlSession();try {// 獲取UserMapper接口UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 注意:數(shù)據(jù)庫中id=1的用戶擁有2個角色,不適合這個例子。// 調(diào)用selectSysUserAndSysRoleById方法,查詢id=1001的用戶及其角色SysUser sysUser = userMapper.selectSysUserAndSysRoleById(1001L);// 期望用戶不為空Assert.assertNotNull(sysUser);// 期望角色不為空Assert.assertNotNull(sysUser.getSysRole());logger.info(sysUser);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();logger.info("sqlSession close successfully ");}}

debug調(diào)測下數(shù)據(jù)


日志

2018-04-29 23:43:15,905 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-29 23:43:15,913 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-04-29 23:43:15,918 INFO [main] (UserMapperTest.java:1007) - selectSysUserAndSysRoleByIdTest 2018-04-29 23:43:16,008 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT u.id, u.user_name userName, u.user_password userPassword, u.user_email userEmail, u.user_info userInfo, u.create_time createTime, u.head_img headImg, r.id "sysRole.id", r.role_name "sysRole.roleName", r.enabled "sysRole.enabled", r.create_by "sysRole.createBy", r.create_time "sysRole.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 = ? 2018-04-29 23:43:16,135 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1001(Long) 2018-04-29 23:43:16,196 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, createTime, headImg, sysRole.id, sysRole.roleName, sysRole.enabled, sysRole.createBy, sysRole.createTime 2018-04-29 23:43:16,198 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用戶, 1, 1, 2018-04-13 21:12:46.0 2018-04-29 23:43:16,215 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 2018-04-29 23:43:16,216 INFO [main] (UserMapperTest.java:1021) - SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=測試用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018, sysRole=SysRole [id=2, roleName=普通用戶, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]] 2018-04-29 23:43:16,222 INFO [main] (UserMapperTest.java:1026) - sqlSession close successfully

通過SQL日志可以看到已經(jīng)查詢出的一條數(shù)據(jù),MyBatis將這條數(shù)據(jù)映射到了兩個類中,像這種通過一次查詢將結(jié)果映射到不同對象的方式,稱之為關(guān)聯(lián)的嵌套結(jié)果查詢。

關(guān)聯(lián)的嵌套結(jié)果映射需要關(guān)聯(lián)多個表將所有需要的值一次性查詢出來, 這種方式的好處是減少數(shù)據(jù)庫的查詢次數(shù),減輕數(shù)據(jù)庫的壓力。 缺點是需要些很復雜的SQL,并且當嵌套結(jié)果更負載時,不容易一次寫正確。 由于要在服務器上將結(jié)果映射到不同的類上,因此也會增加應用服務器的壓力。 當一定會使用到嵌套查詢,并且整個復雜的SQL執(zhí)行速度很快時,建議使用關(guān)聯(lián)的其那套結(jié)果查詢。


方式二:使用resultMap配置一對一映射

UserMapper接口增加接口方法

// 使用resultMap配置一對一映射 SysUser selectSysUserAndSysRoleById2(Long id);

UserMapper.xml增加SQL

<!-- 使用resultMap配置一對一映射 --><resultMap id="userRoleMap" type="com.artisan.mybatis.xml.domain.SysUser"><id column="id" property="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" /><!-- sysRole相關(guān)的屬性 --><result property="sysRole.id" column="role_id"/><result property="sysRole.roleName" column="role_name"/><result property="sysRole.enabled" column="enabled"/><result property="sysRole.createBy" column="create_by"/><result property="sysRole.createTime" column="role_create_time" jdbcType="TIMESTAMP"/></resultMap>

這種配置和上一個配置相似的地方在于,sysRole中的property配置部分使用“sysRole.”前綴,在column部分,為了避免不同表中存在相同的的字段,所有可能重名的列都加了 “role_”前綴。

這種方式配置的時候,還需要再查詢時設(shè)置不同的列名,別名和resultMap配置的colunm一致。 然后使用resultMap配置映射。

<!-- 使用resultMap配置一對一映射 --><select id="selectSysUserAndSysRoleById2" resultMap="userRoleMap">SELECTu.id,u.user_name ,u.user_password ,u.user_email ,u.user_info ,u.create_time ,u.head_img ,r.id role_id,r.role_name ,r.enabled ,r.create_by ,r.create_time role_create_time FROMsys_user uINNER JOIN sys_user_role ur ON u.id = ur.user_idINNER JOIN sys_role r ON ur.role_id = r.idWHEREu.id = #{id}</select>

單元測試

@Testpublic void selectSysUserAndSysRoleById2Test() {logger.info("selectSysUserAndSysRoleById2Test");// 獲取SqlSessionSqlSession sqlSession = getSqlSession();try {// 獲取UserMapper接口UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 注意:數(shù)據(jù)庫中id=1的用戶擁有2個角色,不適合這個例子。// 調(diào)用selectSysUserAndSysRoleById方法,查詢id=1001的用戶及其角色SysUser sysUser = userMapper.selectSysUserAndSysRoleById2(1001L);// 期望用戶不為空Assert.assertNotNull(sysUser);// 期望角色不為空Assert.assertNotNull(sysUser.getSysRole());logger.info(sysUser);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();logger.info("sqlSession close successfully ");}}

日志

2018-04-30 00:52:25,287 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-30 00:52:25,291 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-04-30 00:52:25,295 INFO [main] (UserMapperTest.java:1032) - selectSysUserAndSysRoleById2Test 2018-04-30 00:52:25,390 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id role_id, r.role_name , r.enabled , r.create_by , r.create_time role_create_time 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 = ? 2018-04-30 00:52:25,519 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1001(Long) 2018-04-30 00:52:25,559 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, role_id, role_name, enabled, create_by, role_create_time 2018-04-30 00:52:25,561 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用戶, 1, 1, 2018-04-13 21:12:46.0 2018-04-30 00:52:25,572 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 2018-04-30 00:52:25,573 INFO [main] (UserMapperTest.java:1046) - SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=測試用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018, sysRole=SysRole [id=2, roleName=普通用戶, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]] 2018-04-30 00:52:25,580 INFO [main] (UserMapperTest.java:1051) - sqlSession close successfully

這種方法是不是和第一種使用自動映射處理一對一映射相比起來,resultMap相當麻煩?

事實上 ,resultMap映射是可以被繼承的,因此要先簡化上面的resultMap的配置。 因為我們這個映射文件中本來就存在一個userMap的映射配置,改造如下

<!-- 使用resultMap配置一對一映射 繼承原有的resultMap --><resultMap id="userRoleMap_byExtends" extends="userMap"type="com.artisan.mybatis.xml.domain.SysUser"><!-- sysRole相關(guān)的屬性 --><result property="sysRole.id" column="role_id"/><result property="sysRole.roleName" column="role_name"/><result property="sysRole.enabled" column="enabled"/><result property="sysRole.createBy" column="create_by"/><result property="sysRole.createTime" column="role_create_time" jdbcType="TIMESTAMP"/></resultMap>

使用繼承不僅可以簡化配置,而且當對主表userMap進行修改時也只需要修改一處。 雖然還不是太方便,至少簡潔了一點。 要想更加簡潔,只有派上asscociation了,請往下看

測試過了,就不貼代碼了,github上已經(jīng)托管。


方式三:使用resultMap的asscociation標簽配置一對一映射

在resultMap中,association標簽用于和一個復雜的類型進行關(guān)聯(lián),即用于一對一的關(guān)聯(lián)配置。

UserMapper接口增加接口方法

// 使用resultMap配置一對一映射 resultMap association SysUser selectSysUserAndSysRoleById4(Long id);

UserMapper.xml增加SQL

在上面的基礎(chǔ)上,再做修改,改成association標簽的配置方式。

<!-- 使用resultMap配置一對一映射 使用association --><resultMap id="userRoleMap_byExtendsAndAssociation" extends="userMap"type="com.artisan.mybatis.xml.domain.SysUser"><association property="sysRole" columnPrefix="sysRole_"javaType="com.artisan.mybatis.xml.domain.SysRole"><result 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><!-- 使用resultMap配置一對一映射 result中Map中使用association --><select id="selectSysUserAndSysRoleById4" resultMap="userRoleMap_byExtendsAndAssociation">SELECTu.id,u.user_name ,u.user_password ,u.user_email ,u.user_info ,u.create_time ,u.head_img ,r.id sysRole_id,r.role_name sysRole_role_name,r.enabled sysRole_enabled,r.create_by sysRole_create_by,r.create_time sysRole_create_timeFROMsys_user uINNER JOIN sys_user_role ur ON u.id = ur.user_idINNER JOIN sys_role r ON ur.role_id = r.idWHEREu.id = #{id}</select>

association標簽包含如下主要屬性

  • property:對應實體列中的屬性名,必填
  • javaType:屬性對應的Java類型
  • resultMap:可以直接使用現(xiàn)有的resultMap,從而不需要在這里配置
  • colunmPrefix: 查詢列的前綴,配置前綴后,在子標簽配置result的colunm時,可以省略前綴
  • 其他屬性,略…

因為配置了列的前綴,因此還需要SQL,如上所示。

使用association配置還可以使用resultMap屬性配置成一個已經(jīng)存在的resultMap映射。 我們吧sys_role相關(guān)的映射提取出來,改造如下

<!-- 使用resultMap配置一對一映射 使用association --><resultMap id="roleMap" type="com.artisan.mybatis.xml.domain.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><resultMap id="userRoleMap_byExtendsAndAssociation_ResultMap" extends="userMap"type="com.artisan.mybatis.xml.domain.SysUser"><association property="sysRole" columnPrefix="sysRole_"javaType="com.artisan.mybatis.xml.domain.SysRole" resultMap="roleMap"></association> </resultMap>

到這里,是不是沒有這么麻煩了? 還有一個需要注意的地方:roleMap我們目前是寫在UserMapper.xml中,更合理的應該在RoleMapper.xml中。如果真的在RoleMapper.xml中的話,,通過resultMap來引用的話,就必須要加上命名空間了。 如果不加的話,MyBatis會默認添加調(diào)用者當前命名空間的前綴。

<resultMap id="userRoleMap_byExtendsAndAssociation_ResultMap" extends="userMap"type="com.artisan.mybatis.xml.domain.SysUser"><association property="sysRole" columnPrefix="sysRole_"javaType="com.artisan.mybatis.xml.domain.SysRole" resultMap="com.artisan.mybatis.xml.mapper.RoleMapper.roleMap"></association> </resultMap>

單元測試

@Testpublic void selectSysUserAndSysRoleById4Test() {logger.info("selectSysUserAndSysRoleById4Test");// 獲取SqlSessionSqlSession sqlSession = getSqlSession();try {// 獲取UserMapper接口UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 注意:數(shù)據(jù)庫中id=1的用戶擁有2個角色,不適合這個例子。// 調(diào)用selectSysUserAndSysRoleById4方法,查詢id=1001的用戶及其角色SysUser sysUser = userMapper.selectSysUserAndSysRoleById4(1001L);// 期望用戶不為空Assert.assertNotNull(sysUser);// 期望角色不為空Assert.assertNotNull(sysUser.getSysRole());logger.info(sysUser);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();logger.info("sqlSession close successfully ");}}

日志

2018-05-01 01:08:18,898 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-05-01 01:08:18,905 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-05-01 01:08:18,913 INFO [main] (UserMapperTest.java:1083) - selectSysUserAndSysRoleById4Test 2018-05-01 01:08:19,019 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT u.id, u.user_name , u.user_password , u.user_email , u.user_info , u.create_time , u.head_img , r.id sysRole_id, r.role_name sysRole_role_name, r.enabled sysRole_enabled, r.create_by sysRole_create_by, r.create_time sysRole_create_time 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 = ? 2018-05-01 01:08:19,155 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1001(Long) 2018-05-01 01:08:19,212 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, user_name, user_password, user_email, user_info, create_time, head_img, sysRole_id, sysRole_role_name, sysRole_enabled, sysRole_create_by, sysRole_create_time 2018-05-01 01:08:19,213 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, 2018-04-13 21:12:47.0, <<BLOB>>, 2, 普通用戶, 1, 1, 2018-04-13 21:12:46.0 2018-05-01 01:08:19,231 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 2018-05-01 01:08:19,232 INFO [main] (UserMapperTest.java:1097) - SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=測試用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018, sysRole=SysRole [id=2, roleName=普通用戶, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]] 2018-05-01 01:08:19,239 INFO [main] (UserMapperTest.java:1102) - sqlSession close successfully

方式四:asscociation標簽的嵌套查詢

前面三種方式通過負載的SQL查詢獲取結(jié)果,其實還可以利用簡單的SQL通過多次查詢轉(zhuǎn)換為我們需要的結(jié)果,這種方式與根據(jù)業(yè)務邏輯手動執(zhí)行多次SQL的方式很像,最后將結(jié)果組成一個對象。

場景和情況比較復雜,后續(xù)單獨闡述

總結(jié)

以上是生活随笔為你收集整理的MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。