MyBatis從入門到精通(三):MyBatis XML方式的基本用法之多表查詢

最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,頗有收穫,因而將本身學習的過程以博客形式輸出,若有錯誤,歡迎指正,如幫助到你,不勝榮幸!java

1. 多表查詢

上篇博客中,咱們示例的2個查詢都是單表查詢,但實際的業務場景確定是須要多表查詢的,好比如今有個需求:git

查詢某個用戶擁有的全部角色。這個需求要涉及到sys_user,sys_user_role,sys_role三張表,如何實現呢?github

首先,在SysUserMapper接口中定義以下方法。sql

/**
 * 根據用戶id獲取角色信息
 *
 * @param userId
 * @return
 */
List<SysRole> selectRolesByUserId(Long userId);

而後打開對應的SysUserMapper.xml文件,添加以下select語句:微信

<select id="selectRolesByUserId" resultType="com.zwwhnly.mybatisaction.model.SysRole">
    SELECT r.id,
           r.role_name   roleName,
           r.enabled,
           r.create_by   createBy,
           r.create_time 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 = #{userId}
</select>

細心的讀者可能會發現,咱們雖然使用到了多表查詢,可是resultType設置的仍然是單表,即只包含角色表的信息。mybatis

若是我但願這個查詢語句同時返回SysUser表的user_name字段呢,該如何設置resultType?app

方法1:直接在SysRole實體類中添加userName字段。工具

private String userName;

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

此時resultType不用修改。學習

方法2:新建擴展類,在擴展類中添加userName字段。測試

package com.zwwhnly.mybatisaction.model;

public class SysRoleExtend extends SysRole {
    private String userName;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

此時須要將resultType修改成:com.zwwhnly.mybatisaction.model.SysRoleExtend。

這種方式比較適合須要少許額外字段的場景。若是須要其餘表的大量字段,可使用方式3或者方式4,我的推薦使用方式4。

方法3:在SysRole實體類中添加SysUser類型的字段。

private SysUser sysUser;

public SysUser getSysUser() {
   return sysUser;
}

public void setSysUser(SysUser sysUser) {
    this.sysUser = sysUser;
}

此時resultType不用修改。

方法4(推薦使用):新建擴展類,在擴展類中添加SysUser類型的字段。

書中推薦的是方式3,方式4是我我的認爲更好的方式,由於實體類通常由工具自動生成,增長了字段後,後續容易忘記致使被覆蓋掉。

package com.zwwhnly.mybatisaction.model;

public class SysRoleExtend extends SysRole {
    private SysUser sysUser;

    public SysUser getSysUser() {
        return sysUser;
    }

    public void setSysUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }
}

此時須要將resultType修改成:com.zwwhnly.mybatisaction.model.SysRoleExtend。

此時xml中的查詢語句以下。

<select id="selectRolesByUserId" resultType="com.zwwhnly.mybatisaction.model.SysRoleExtend">
    SELECT r.id,
           r.role_name   roleName,
           r.enabled,
           r.create_by   createBy,
           r.create_time createTime,
           u.user_name   "sysUser.userName",
           u.user_email   "sysUser.userEmail"
    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 = #{userId}
</select>

在SysUserMapperTest中添加測試代碼以下。

@Test
public void testSelectRolesByUserId() {
    SqlSession sqlSession = getSqlSession();

    try {
        SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);

        List<SysRole> sysRoleList = sysUserMapper.selectRolesByUserId(1L);

        Assert.assertNotNull(sysRoleList);
        Assert.assertTrue(sysRoleList.size() > 0);
    } finally {
        sqlSession.close();
    }
}

運行該測試方法,輸入日誌以下。

DEBUG [main] - ==> Preparing: SELECT r.id, r.role_name roleName, r.enabled, r.create_by createBy, r.create_time createTime, u.user_name "sysUser.userName", u.user_email "sysUser.userEmail" 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 = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, roleName, enabled, createBy, createTime, sysUser.userName, sysUser.userEmail

TRACE [main] - <== Row: 1, 管理員, 1, 1, 2019-06-27 18:21:12.0, admin, admin@mybatis.tk

TRACE [main] - <== Row: 2, 普通用戶, 1, 1, 2019-06-27 18:21:12.0, admin, admin@mybatis.tk

DEBUG [main] - <== Total: 2

2. 多個接口參數的用法

2.1 參數類型是基本類型

截止目前,咱們定義的方法都只有1個參數,要麼是隻有1個基本類型的參數,好比selectById(Long id);。

要麼是隻有1個對象做爲參數,即將多個參數合併成了1個對象。

但有些場景下,好比只有2個參數,沒有必要爲這2個參數再新建一個對象,好比咱們如今須要根據用戶的id和角色的狀態來獲取用戶的全部角色,那麼該如何使用呢?

首先,在接口SysUserMapper中添加以下方法。

/**
 * 根據用戶id和角色的enabled狀態獲取用戶的角色
 *
 * @param userId
 * @param enabled
 * @return
 */
List<SysRole> selectRolesByUserIdAndRoleEnabled(Long userId,Integer enabled);

而後,打開對應的SysUserMapper.xml文件,添加以下代碼。

<select id="selectRolesByUserIdAndRoleEnabled" resultType="com.zwwhnly.mybatisaction.model.SysRole">
    SELECT r.id,
           r.role_name   roleName,
           r.enabled,
           r.create_by   createBy,
           r.create_time 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 = #{userId} AND r.enabled = #{enabled}
</select>

在SysUserMapperTest測試類中,添加以下測試方法。

@Test
public void testselectRolesByUserIdAndRoleEnabled() {
    SqlSession sqlSession = getSqlSession();

    try {
        SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
        List<SysRole> sysRoleList = sysUserMapper.selectRolesByUserIdAndRoleEnabled(1L, 1);

        Assert.assertNotNull(sysRoleList);
        Assert.assertTrue(sysRoleList.size() > 0);
    } finally {
        sqlSession.rollback();
        sqlSession.close();
    }
}

運行該測試方法,發現報以下錯誤。

報錯信息中說未找到參數userId,可用的參數是[0,1,param1,param2],也就是說咱們將代碼修改成:

WHERE u.id = #{0} AND r.enabled = #{1}

或者修改成:

WHERE u.id = #{param1} AND r.enabled = #{param2}

這麼使用是能夠測試經過的,不過這樣使用,代碼閱讀起來不夠友好,所以並不推薦這麼使用。

推薦在接口方法的參數前添加@Param註解,以下所示:

/**
 * 根據用戶id和角色的enabled狀態獲取用戶的角色
 *
 * @param userId
 * @param enabled
 * @return
 */
List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);

運行剛剛添加的測試方法,測試經過,輸出日誌以下:

DEBUG [main] - ==> Preparing: SELECT r.id, r.role_name roleName, r.enabled, r.create_by createBy, r.create_time 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 = ? AND r.enabled = ?

DEBUG [main] - ==> Parameters: 1(Long), 1(Integer)

TRACE [main] - <== Columns: id, roleName, enabled, createBy, createTime

TRACE [main] - <== Row: 1, 管理員, 1, 1, 2019-06-27 18:21:12.0

TRACE [main] - <== Row: 2, 普通用戶, 1, 1, 2019-06-27 18:21:12.0

DEBUG [main] - <== Total: 2

2.2 參數類型是對象

爲了演示參數類型是對象的使用方法,咱們在接口SysUserMapper中添加以下方法:

/**
 * 根據用戶id和角色的enabled狀態獲取用戶的角色
 *
 * @param user
 * @param role
 * @return
 */
List<SysRole> selectRolesByUserAndRole(@Param("user") SysUser user, @Param("role") SysRole role);

此時對應的xml中的語句爲:

<select id="selectRolesByUserAndRole" resultType="com.zwwhnly.mybatisaction.model.SysRole">
    SELECT r.id,
    r.role_name   roleName,
    r.enabled,
    r.create_by   createBy,
    r.create_time 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 = #{user.id} AND r.enabled = #{role.enabled}
</select>

3. 源碼及參考

源碼地址:https://github.com/zwwhnly/mybatis-action.git,歡迎下載。

劉增輝《MyBatis從入門到精通》

4. 最後

打個小廣告,歡迎掃碼關注微信公衆號:「申城異鄉人」,按期分享Java技術乾貨,讓咱們一塊兒進步。

相關文章
相關標籤/搜索