内容简介:最近在读刘增辉老师所著的《MyBatis从入门到精通》一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸!上篇博客中,我们示例的2个查询都是单表查询,但实际的业务场景肯定是需要多表查询的,比如现在有个需求:查询某个用户拥有的所有角色。这个需求要涉及到sys_user,sys_user_role,sys_role三张表,如何实现呢?
最近在读刘增辉老师所著的《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(); } }
运行该测试方法,发现报如下错误。
报错信息中说未找到参数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 ,欢迎下载。
4. 参考
刘增辉《MyBatis从入门到精通》
以上所述就是小编给大家介绍的《MyBatis从入门到精通(三):MyBatis XML方式的基本用法之多表查询》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- MyBatis从入门到精通(五):MyBatis 注解方式的基本用法
- MyBatis从入门到精通(五):MyBatis 注解方式的基本用法
- MyBatis从入门到精通(二):MyBatis XML方式的基本用法之Select
- MyBatis从入门到精通(八):MyBatis动态Sql之foreach标签的用法
- MyBatis从入门到精通(六):MyBatis动态Sql之if标签的用法
- MyBatis从入门到精通(二):MyBatis XML方式的基本用法之Select
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Release It!
Michael T. Nygard / Pragmatic Bookshelf / 2007-03-30 / USD 34.95
“Feature complete” is not the same as “production ready.” Whether it’s in Java, .NET, or Ruby on Rails, getting your application ready to ship is only half the battle. Did you design your system to......一起来看看 《Release It!》 这本书的介绍吧!