mybatis collection标签_一对多的关系,在MyBatis中如何映射?
# 使用collection標簽
需求:根據(jù)用戶id查詢用戶信息的同時獲取用戶擁有的角色,一個用戶可以擁有1個或多個角色。
一般情況下,不建議直接修改數(shù)據(jù)庫表對應(yīng)的實體類。
所以這里我們延用之前博客中新建的類SysUserExtend,并添加如下代碼,如下所示:
/** * 用戶的角色集合 */private List sysRoleList;public ListgetSysRoleList() { return sysRoleList;}public void setSysRoleList(List sysRoleList) { this.sysRoleList = sysRoleList;}然后,我們在接口SysUserMapper中添加如下方法:
/** * 獲取所有的用戶以及對應(yīng)的所有角色 * * @return */List selectAllUserAndRoles();接著,在對應(yīng)的SysUserMapper.xml中添加如下代碼:
<resultMap id="userRoleListMap" type="com.zwwhnly.mybatisaction.model.SysUserExtend" extends="sysUserMap"> <collection property="sysRoleList" columnPrefix="role_" ofType="com.zwwhnly.mybatisaction.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"/> collection>resultMap>因為我們在前面的博客中已經(jīng)建過角色表的roleMap:
<resultMap id="roleMap" type="com.zwwhnly.mybatisaction.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>所以上面的collection標簽可以簡化為:
<collection property="sysRoleList" columnPrefix="role_" resultMap="com.zwwhnly.mybatisaction.mapper.SysRoleMapper.roleMap">collection>新建接口對應(yīng)的查詢代碼,使用上面新建的userRoleListMap,如下所示:
SELECT u.id, u.user_name, u.user_password, u.user_email, u.create_time, r.id role_id, r.role_name role_role_name, r.enabled role_enabled, r.create_by role_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最后,在SysUserMapperTest測試類中添加如下測試方法:
@Testpublic void testSelectAllUserAndRoles() { SqlSession sqlSession = getSqlSession(); try { SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class); List sysUserList = sysUserMapper.selectAllUserAndRoles(); System.out.println("用戶數(shù):" + sysUserList.size()); for (SysUserExtend sysUser : sysUserList) { System.out.println("用戶名:" + sysUser.getUserName()); for (SysRole sysRole : sysUser.getSysRoleList()) { System.out.println("角色名:" + sysRole.getRoleName()); } } } finally { sqlSession.close(); }}運行測試代碼,測試通過,輸出日志如下:
DEBUG [main] - ==> Preparing: SELECT u.id, u.user_name, u.user_password, u.user_email, u.create_time, r.id role_id, r.role_name role_role_name, r.enabled role_enabled, r.create_by role_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.idDEBUG [main] - ==> Parameters:TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time, role_id, role_role_name, role_enabled, role_create_by, role_create_timeTRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0, 1, 管理員, 1, 1, 2019-06-27 18:21:12.0TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0, 2, 普通用戶, 1, 1, 2019-06-27 18:21:12.0TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0, 2, 普通用戶, 1, 1, 2019-06-27 18:21:12.0DEBUG [main] - <== Total: 3用戶數(shù):2用戶名:admin角色名:管理員角色名:普通用戶用戶名:test角色名:普通用戶# MyBatis合并規(guī)則
觀察上面的日志,我們的Sql語句查詢到了3條數(shù)據(jù),在數(shù)據(jù)庫查詢的話,也是返回如下的數(shù)據(jù):
但經(jīng)過MyBatis配置的映射到,最后合并為了2個用戶,其中第1個用戶包含了2個角色,第2個用戶包含了1個角色,那么MyBatis是根據(jù)什么規(guī)則合并的呢?
MyBatis在處理結(jié)果的時候,會判斷結(jié)果是否相同,如果是相同的結(jié)果,則只會保留第一個結(jié)果,所以關(guān)鍵點就是MyBatis如何判斷結(jié)果是否相同。
判斷結(jié)果是否相同時,最簡單的情況就是在映射配置中至少有1個id標簽,上面使用的sysUserMap就配置了id標簽:
<id property="id" column="id"/>一般情況下,id標簽配置的字段為表的主鍵,如果是聯(lián)合主鍵,可以配置多個id標簽。
id標簽的作用就是在嵌套的映射配置時判斷數(shù)據(jù)是否相同,當配置id標簽時,MyBatis只需要逐條比較所有數(shù)據(jù)中id標簽配置的字段值是否相同即可。
也可以不配置id標簽,將上面的代碼修改為:
<result property="id" column="id"/>使用result不會影響查詢結(jié)果,但是此時MyBatis就要對所有字段進行比較,因此當字段數(shù)為M時,如果查詢結(jié)果有N條,就需要比較M*N次,如果配置了id標簽,只需要比較N次即可,所以要盡可能的配置id標簽。
結(jié)合上面的例子,因為Sql的查詢結(jié)果中,前2條數(shù)據(jù)中用戶的id是相同的,所以會合并為1個用戶,所以最終的結(jié)果是2個用戶。
為了更清楚的理解id標簽的作用,我們將sysUserMap臨時修改為:
<resultMap id="sysUserMap" type="com.zwwhnly.mybatisaction.model.SysUser"> <id property="userPassword" column="user_password"/> <result property="id" column="id"/> <result property="userName" column="user_name"/> <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>運行測試方法,輸出的部分日志如下:
用戶數(shù):1用戶名:admin角色名:管理員角色名:普通用戶因為3個用戶的密碼都是123456,所以查詢到的3條數(shù)據(jù)只保留了第一個用戶admin,包含了2個角色。
有的同學(xué)也許會問,為什么不是擁有3個角色呢?
這是因為MyBatis會對嵌套查詢的每一級對象都進行屬性比較,MyBatis會先比較頂層的對象,如果SysUser部分相同,就繼續(xù)比較SysRole部分,如果SysRole不同,就會增加一個SysRole,如果相同就保留前一個。
如果SysRole還有下一級,依次按照規(guī)則去比較。
上面的“普通用戶”角色重復(fù)了,所以只保留了前1個,導(dǎo)致最終的結(jié)果中只包含2個角色而不是3個。
#? 源碼及參考
源碼地址:https://github.com/zwwhnly/mybatis-action.git,歡迎下載。
劉增輝《MyBatis從入門到精通》
作者:申城異鄉(xiāng)人
來源:https://www.cnblogs.com/zwwhnly/p/11194028.html
?往期推薦?
?
- Github移動端,IDEA 2019.3.4,JDK 14,都發(fā)布了,趕快嘗鮮
- MyBatis中如何使用association標簽實現(xiàn)嵌套查詢
- 有點慘!百度工程師挖礦:4 個月控制 155 臺服務(wù)器挖礦,獲利 10萬,被判 3 年
點擊
總結(jié)
以上是生活随笔為你收集整理的mybatis collection标签_一对多的关系,在MyBatis中如何映射?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。