MyBatis XML方式的基本用法之多表查询功能的示例代码

 更新时间:2019年07月03日 10:36:48   作者:申城异乡人  
这篇文章主要介绍了MyBatis XML方式的基本用法之多表查询功能的示例代码,本文通过示例文字相结合的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

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

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


报错信息中说未找到参数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 XML方式的基本用法之多表查询功能的示例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关文章

  • Java常用加密算法实例总结

    Java常用加密算法实例总结

    这篇文章主要介绍了Java常用加密算法,结合实例形式总结分析了base64、md5、sha、rsa、des等加密算法实现技巧,需要的朋友可以参考下
    2017-10-10
  • Spring AspectJ AOP框架注解原理解析

    Spring AspectJ AOP框架注解原理解析

    这篇文章主要介绍了Spring AspectJ AOP框架注解原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Springboot返回的json屏蔽某些属性的操作

    Springboot返回的json屏蔽某些属性的操作

    这篇文章主要介绍了Springboot返回的json屏蔽某些属性的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java中Object类的理解和使用

    Java中Object类的理解和使用

    Object类是java.lang包下的核心类,Object类是所有类的父类,何一个类时候如果没有明确的继承一个父类的话,那么它就是Object的子类,本文将通过代码示例详细介绍一下Java中Object类的理解和使用,需要的朋友可以参考下
    2023-06-06
  • SpringMVC中Invalid bound statement (not found)常见报错问题解决

    SpringMVC中Invalid bound statement (not f

    本文主要介绍了SpringMVC中Invalid bound statement (not found)常见报错问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Java微信公众平台开发(14) 微信web开发者工具使用

    Java微信公众平台开发(14) 微信web开发者工具使用

    这篇文章主要为大家详细介绍了Java微信公众平台开发第十四步,微信web开发者工具的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述

    java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述

    算法是程序设计的精髓,程序设计的实质就是构造解决问题的算法,将其解释为计算机语言。
    2009-06-06
  • WebSocket实现系统后台消息实时通知功能

    WebSocket实现系统后台消息实时通知功能

    在现代Web应用中,提供实时通知对于改善用户体验至关重要,WebSocket技术允许建立双向通信通道,从系统后台将消息实时传送给系统用户,下面我们就来深入探讨一下如何使用WebSocket来实现这一功能吧
    2023-10-10
  • java8 使用stream排序空字段排在前面或后面

    java8 使用stream排序空字段排在前面或后面

    这篇文章主要介绍了java8 使用stream排序空字段排在前面或后面的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Java如何实现压缩文件与解压缩zip文件

    Java如何实现压缩文件与解压缩zip文件

    这篇文章主要介绍了Java如何实现压缩文件与解压缩zip文件问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12

最新评论