MyBatis高級查詢

使用自動映射處理一對一映射

一個用戶只能擁有一個角色删壮。

使用自動映射就是通過別名讓MyBatis自動將值匹配到相應(yīng)的字段上,簡單的別名映射如:
user_name對應(yīng)UserName。除此之外Mybatis還支持復(fù)雜的屬性映射库糠,可以多層嵌套,例如將:
role.role_name映射到role.roleName上。MyBatis會先查找role屬性蜡峰,如果存在role屬性就創(chuàng)建role對象,然后在role對象中繼續(xù)查找roleName,將role_name的值綁定到role的roleName屬性上事示。

下面根據(jù)自動映射規(guī)則早像,在UserMapper中增加如下方法。


   <select id="selectUserAndRoleById" resultMap="userRoleMap">
        SELECT
            u.id,
            u.user_name,
            u.user_password,
            u.user_email,
            u.user_info,
            u.head_img,
            u.create_time,
            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>

使用resultMap配置一一映射

先寫好resultMap,然后查詢語句也與自動映射的不太一樣

<resultMap id="userMap" type="pers.congcong.myBatis2.pojos.SysUser">
        <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="roleMap" type="pers.congcong.myBatis2.pojos.SysRole">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="role_name" jdbcType="VARCHAR" property="roleName" />
        <result column="enabled" jdbcType="INTEGER" property="enabled" />
        <result column="create_by" jdbcType="BIGINT" property="createBy" />
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    </resultMap>

    <resultMap id="userRoleMap" extends="userMap" type="pers.congcong.myBatis2.pojos.SysUser">
        <result column="id" jdbcType="BIGINT" property="id" />
        <result column="role_name" jdbcType="VARCHAR" property="roleName" />
        <result column="enabled" jdbcType="INTEGER" property="enabled" />
        <result column="create_by" jdbcType="BIGINT" property="createBy" />
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    </resultMap>


    <select id="selectUserAndRoleById" resultMap="userRoleMap">
        SELECT
            u.id,
            u.user_name,
            u.user_password,
            u.user_email,
            u.user_info,
            u.head_img,
            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
        WHERE u.id = #{id}
    </select>

第三種 使用resultMap的association標簽一對一映射

查詢語句跟使用resultMap的一樣肖爵,只不過將resultMap封裝了卢鹦,然后用association標簽引用
代碼如下:

    <resultMap id="userMap" type="pers.congcong.myBatis2.pojos.SysUser">
        <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="roleMap" type="pers.congcong.myBatis2.pojos.SysRole">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="role_name" jdbcType="VARCHAR" property="roleName" />
        <result column="enabled" jdbcType="INTEGER" property="enabled" />
        <result column="create_by" jdbcType="BIGINT" property="createBy" />
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    </resultMap>

    <resultMap id="userRoleMap" extends="userMap" type="pers.congcong.myBatis2.pojos.SysUser">
        <association property="sysRole" columnPrefix="role_" resultMap="roleMap" />
    </resultMap>

第四種 association標簽的嵌套查詢:

除了前面3中通過復(fù)雜SQL查詢獲取結(jié)果,還可以利用簡單SQL通過多次查詢轉(zhuǎn)換為我們的結(jié)果劝堪,這種方式與根據(jù)業(yè)務(wù)的邏輯手動執(zhí)行多次SQL的方式相像冀自,最后會合成一個對象。

association標簽的嵌套查詢
實則上是將select封裝好秒啦,然后通過association調(diào)用熬粗。
association標簽的嵌套查詢常用的屬性如下:
select:另一個映射查詢的ID,MyBatis會額外執(zhí)行這個查詢獲取這個對象的結(jié)果余境。
column:列名驻呐,將主查詢中列的結(jié)果作為嵌套查詢的參數(shù),配置方法如:
column={propl=coll, prop2=coll2},prop1和prop2將作為嵌套查詢的參數(shù)芳来。
fetchType:數(shù)據(jù)的加載方式含末,可選值為lazy和eager,分別為延遲加載和積極加載即舌,這個配置會覆蓋全局的lazyLodingEnable配置佣盒。

看得差不多,不抄書了顽聂,上代碼:
····

<resultMap id="userRoleMapSelect" type="pers.congcong.myBatis2.pojos.SysUser" extends="userMap">
    <association property="sysRole" fetchType="lazy" column="{id = role_id}"         select="pers.congcong.myBatis2.mappers.RoleMapper.selectById"/>
</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>

····

測試代碼:

   @Test
    public void testSelectUserAndRoleById() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectUserAndRoleByIdSelect(1001l);

            System.out.println("調(diào)用user.getSysRole()");

            Assert.assertNotNull(sysUser.getSysRole());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

結(jié)果:


fetchType="lazy"

這里使用fetchType為lazy肥惭,要配置這個屬性的時候要修改mybatis-config.xml
添加

 <setting name="aggressiveLazyLoading" value="false"/>

就可以了。

一對多映射

collection集合的嵌套結(jié)果映射:

和association類似紊搪,集合的嵌套結(jié)果就是通過一次SQL查詢將所有的結(jié)果查詢出來蜜葱,然后通過配置的結(jié)果映射,將數(shù)據(jù)映射到不同的對象中去耀石。在一對多的關(guān)系中笼沥,主表的一條數(shù)據(jù)會對應(yīng)關(guān)聯(lián)表中的多條數(shù)據(jù),因此娶牌,一般查詢時會查詢出多個結(jié)果奔浅,按照一對多的數(shù)據(jù)結(jié)果存儲數(shù)據(jù)的時候,最終的結(jié)果會小于查詢的總記錄數(shù)诗良。

需求:
一個用戶擁有多個角色汹桦,每個角色又擁有多個權(quán)限。所以要漸進式的實現(xiàn)一個SQL鉴裹,查詢出所有用戶和用戶擁有的角色舞骆,以及角色所包含的所有權(quán)限信息的兩層嵌套結(jié)果钥弯。

解決:
首先在Role中添加角色的集合:

private List<SysRole> sysRoleList;
以及setter,getter方法督禽。

然后在UserMapper.xml中創(chuàng)建resultMap脆霎,select方法,代碼如下:

    <resultMap id="userRoleListMap" extends="userMap" type="pers.congcong.myBatis2.pojos.SysUser">
        <collection property="sysRoleList" columnPrefix="role_" resultMap="pers.congcong.myBatis2.mappers.RoleMapper.roleMap"/>
    </resultMap>

    <select id="selectAllUserAndRoles" resultMap="userRoleListMap">
        SELECT
            u.id,
            u.user_name,
            u.user_password,
            u.user_email,
            u.user_info,
            u.head_img,
            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
    </select>

然后在UserMapper中添加selectAllUserAndRoles接口

    /**
     * 選擇role的List
     * @return
     */
    List<SysUser> selectAllUserAndRoles();

測試代碼跟上面的差不多狈惫,就不占有版面了睛蛛。
需要注意的是在配置resultMap的時候,需要配置id胧谈,
沒有配置id時忆肾,MyBatis就會把resultMap中配置的所有字段進行比較,如果所有字段的值都相同就合并菱肖,只要有一個字段不同客冈,就不合并。

接著添加第二層一對多的關(guān)系稳强,Role跟privilege的關(guān)系:
在Role類中添加privilege集合场仲,getter,setter方法:

List<SysPrivilege> privileges;
    public List<SysPrivilege> getPrivileges() {
        return privileges;
    }

    public void setPrivileges(List<SysPrivilege> privileges) {
        this.privileges = privileges;
    }

然后添加PrivilegeMapper.xml,####記得要注意xml的文件名跟包路勁要跟對應(yīng)接口的接口名和路徑一致

<mapper namespace="pers.congcong.myBatis2.mappers.PrivilegeMapper">
  <resultMap id="privilegeMap" type="pers.congcong.myBatis2.pojos.SysPrivilege">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="privilege_name" jdbcType="VARCHAR" property="privilegeName" />
    <result column="privilege_url" jdbcType="VARCHAR" property="privilegeUrl" />
  </resultMap>

在RoleMapper.xml中添加resultMap配置退疫。

    <resultMap id="rolePrivilegeListMap" type="pers.congcong.myBatis2.pojos.SysRole" extends="roleMap">
        <collection property="privileges" columnPrefix="privilege_"
                    resultMap="pers.congcong.myBatis2.mappers.PrivilegeMapper.privilegeMap"/>
    </resultMap>

最后修改SQL進行關(guān)聯(lián)渠缕。
這個SQL看起來有點別扭:

   <select id="selectAllUserAndRoles" resultMap="userRoleListMap">
        SELECT
            u.id,
            u.user_name,
            u.user_password,
            u.user_email,
            u.user_info,
            u.head_img,
            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",
            p.id role_privilege_id,
            p.privilege_name role_privilege_privilege_name,
            p.privilege_url role_privilege_privilege_url
        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
            INNER JOIN sys_role_privilege rp on rp.role_id = r.id
            INNER JOIN sys_privilege p on p.id = rp.privilege_id
    </select>

最后寫一個測試類:

    @Test
    public void testSelectAllUserAndRoles() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            List<SysUser> sysUserList = userMapper.selectAllUserAndRoles();

            Assert.assertNotNull(sysUserList);
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

debug一下,運行結(jié)果如圖:


兩次一對多映射

collection集合的嵌套查詢

我們知道association關(guān)聯(lián)的嵌套查詢這種方式會執(zhí)行額外的SQL查詢蹄咖,映射配置會簡單很多褐健。

下面以自下而上的過程來實現(xiàn)這樣一個兩層嵌套的功能付鹿,由于面板關(guān)系澜汤,這里我只貼一層的代碼。

    <resultMap id="rolePrivilegeListMapSelect" extends="roleMap" type="pers.congcong.myBatis2.pojos.SysRole">
        <collection property="privileges" fetchType="lazy" column="{roleId=id}" select="pers.congcong.myBatis2.mappers.PrivilegeMapper.selectPrivilegeByRoleId"/>
    </resultMap>

    <select id="selectRoleByUserId" resultMap="rolePrivilegeListMapSelect">
        SELECT
          r.id,
          r.role_name,
          r.enabled,
          r.create_time,
          r.create_by
        FROM sys_role r
        INNER JOIN sys_user_role ur ON ur.role_id = r.id
        WHERE ur.user_id = #{userId}
    </select>

PrivilegeMapper跟UserMapper里面的嵌套也是這樣寫

然后添加接口舵匾,怎樣添加接口上面也講過了俊抵,直接看測試結(jié)果圖吧:


MyBatis的三層嵌套查詢

通過這幾個例子,相信我應(yīng)該對這種映射結(jié)果的配置略懂一二了坐梯,這里值得注意的是collection的用法跟association的用法徽诲。還有延遲加載。OK吵血,碼完了谎替。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蹋辅,隨后出現(xiàn)的幾起案子钱贯,更是在濱河造成了極大的恐慌,老刑警劉巖侦另,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秩命,死亡現(xiàn)場離奇詭異尉共,居然都是意外死亡,警方通過查閱死者的電腦和手機弃锐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門袄友,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人霹菊,你說我怎么就攤上這事剧蚣。” “怎么了浇辜?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵券敌,是天一觀的道長。 經(jīng)常有香客問我柳洋,道長待诅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任熊镣,我火速辦了婚禮卑雁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绪囱。我一直安慰自己测蹲,他們只是感情好,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布鬼吵。 她就那樣靜靜地躺著扣甲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪齿椅。 梳的紋絲不亂的頭發(fā)上琉挖,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音涣脚,去河邊找鬼示辈。 笑死,一個胖子當著我的面吹牛遣蚀,可吹牛的內(nèi)容都是我干的矾麻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼芭梯,長吁一口氣:“原來是場噩夢啊……” “哼险耀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起玖喘,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤甩牺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芒涡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柴灯,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡卖漫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了赠群。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羊始。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖查描,靈堂內(nèi)的尸體忽然破棺而出突委,到底是詐尸還是另有隱情,我是刑警寧澤冬三,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布匀油,位于F島的核電站,受9級特大地震影響勾笆,放射性物質(zhì)發(fā)生泄漏敌蚜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一窝爪、第九天 我趴在偏房一處隱蔽的房頂上張望弛车。 院中可真熱鬧,春花似錦蒲每、人聲如沸纷跛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贫奠。三九已至,卻和暖如春望蜡,著一層夾襖步出監(jiān)牢的瞬間唤崭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工泣特, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浩姥,地道東北人挑随。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓状您,卻偏偏與公主長得像,于是被迫代替她去往敵國和親兜挨。 傳聞我的和親對象是個殘疾皇子膏孟,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容