欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MyBatis从入门到精通(三):MyBatis XML方式的基本用法之多表查询

程序员文章站 2023-11-04 11:30:22
最近在读刘增辉老师所著的《MyBatis从入门到精通》一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 1. 多表查询 上篇博客中,我们示例的2个查询都是单表查询,但实际的业务场景肯定是需要多表查询的,比如现在有个需求: 查询某个用户拥有的所有角色。这个 ......

最近在读刘增辉老师所著的《mybatis从入门到精通》一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸!

1. 多表查询

上篇博客中,我们示例的2个查询都是单表查询,但实际的业务场景肯定是需要多表查询的,比如现在有个需求:

查询某个用户拥有的所有角色。这个需求要涉及到sys_user,sys_user_role,sys_role三张表,如何实现呢?

首先,在sysusermapper接口中定义如下方法。

/**
 * 根据用户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设置的仍然是单表,即只包含角色表的信息。

如果我希望这个查询语句同时返回sysuser表的user_name字段呢,该如何设置resulttype?

方法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();
    }
}

运行该测试方法,发现报如下错误。

MyBatis从入门到精通(三):MyBatis XML方式的基本用法之多表查询

报错信息中说未找到参数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. 源码

源码地址:,欢迎下载。

4. 参考

刘增辉《mybatis从入门到精通》