MyBatis从入门到精通(第2章):MyBatis XML方式的基本用法【select用法】

本章将通过完成权限管理的常见业务来学习 MyBatis XML方式的基本用法。

这个权限管理控制,采用RBAC(Role-Based Access Control,基于角色的访问控制)方式。

2.1 一个简单的权限控制需求

权限管理的需求:一个用户拥有若干角色,一个角色拥有若干权限,权限就是对某个模块资源的某种操作(增、删、改、查),这便是“用户-角色-权限”的授权模型。

采用RBAC授权模型,用户与角色之间、角色与权限之间,一般是多对多的关系。

2.1.1 创建数据库表

 在已经创建好的 testmybatis 数据库中执行如下SQL脚本。(如何通过SQL脚本用Navicat管理数据库,请参考我上一篇博客的 1.3.1  准备数据库

 执行如下脚本创建上图中的5张表:用户表,角色表,权限表,用户角色关联表,角色权限关联表。

 本书中此处没有创建表之间的外键关系,对于表之间的关系,会通过业务逻辑来进行限制。

-- --2.1.1数据库创建5张表
CREATE TABLE sys_user(
  id BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  user_name VARCHAR(50) COMMENT '用户名',
  user_password VARCHAR(50) COMMENT '密码',
  user_email VARCHAR(50) COMMENT '邮箱',
  user_info TEXT COMMENT '简介',
  head_img BLOB COMMENT '头像',
  create_time DATETIME COMMENT '创建时间',
  PRIMARY KEY (id)
);
ALTER TABLE sys_user COMMENT '用户表';

CREATE TABLE sys_role
(
  id BIGINT NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  role_name VARCHAR(50) COMMENT '角色名',
  enabled INT COMMENT '有效标志',
  create_by BIGINT COMMENT '创建人',
  create_time DATETIME COMMENT '创建时间',
  PRIMARY KEY (id)
);
ALTER TABLE sys_role COMMENT '角色表';

CREATE TABLE sys_privilege
(
  id BIGINT NOT NULL AUTO_INCREMENT COMMENT '权限ID',
  privilege_name VARCHAR(50) COMMENT '权限名称',
  privilege_url VARCHAR(200) COMMENT '权限URL',
  PRIMARY KEY (id)
);
ALTER TABLE sys_privilege COMMENT '权限表';

CREATE TABLE sys_user_role
(
  user_id BIGINT COMMENT '用户ID',
  role_id BIGINT COMMENT '角色ID'
);
ALTER TABLE sys_user_role COMMENT '用户角色关联表';

CREATE TABLE sys_role_privilege
(
  role_id BIGINT COMMENT '角色ID',
  privilege_id BIGINT COMMENT '权限ID'
);
ALTER TABLE sys_role_privilege COMMENT '角色权限关联表';
View Code-- --2.1.1数据库创建5张表

为了方便后面的测试,接着在表中用SQL脚本插入一些测试数据。 

-- --2.1.1插入测试数据
INSERT INTO `sys_user` VALUES ('1','admin','123456','admin@mybatis.tk','管理员',NULL,'2019-07-12 17:00:58');
INSERT INTO `sys_user` VALUES ('1001','test','123456','test@mybatis.tk','测试用户',NULL,'2019-07-12 17:01:52');

INSERT INTO `sys_role` VALUES ('1','管理员','1','1','2019-11-17 18:54:48');
INSERT INTO `sys_role` VALUES ('2','普通用户','1','1',current_timestamp);

INSERT INTO `sys_user_role` VALUES ('1','1');
INSERT INTO `sys_user_role` VALUES ('1','2');
INSERT INTO `sys_user_role` VALUES ('1001','2');

INSERT INTO `sys_privilege` VALUES ('1','用户管理','/users');
INSERT INTO `sys_privilege` VALUES ('2','角色管理','/roles');
INSERT INTO `sys_privilege` VALUES ('3','系统日志','/logs');
INSERT INTO `sys_privilege` VALUES ('4','人员维护','/persons');
INSERT INTO `sys_privilege` VALUES ('5','单位维护','/companies');

INSERT INTO `sys_role_privilege` VALUES ('1','1');
INSERT INTO `sys_role_privilege` VALUES ('1','3');
INSERT INTO `sys_role_privilege` VALUES ('1','2');
INSERT INTO `sys_role_privilege` VALUES ('2','4');
INSERT INTO `sys_role_privilege` VALUES ('2','5');
View Code-- --2.1.1插入测试数据

 

2.1.2  创建实体类

在包(package) cn.bjut.simple.model 下依次创建这5张数据库表 未来(查询结果)映射的实体类。 

用户表

package cn.bjut.simple.model;

import java.util.Date;

public class SysUser {
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

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

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public String getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(String userInfo) {
        this.userInfo = userInfo;
    }

    public byte[] getHeadImg() {
        return headImg;
    }

    public void setHeadImg(byte[] headImg) {
        this.headImg = headImg;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**      * 用户ID    */     private Long id;
    /**      * 用户名    */     private String userName;
    /**      * 密码      */     private String userPassword;
    /**      * 邮箱      */     private String userEmail;
    /**      * 简介      */     private String userInfo;
    /**      * 头像      */     private byte[] headImg;
    /**      * 创建时间  */     private Date createTime;



}
public class SysUser

用户与角色关联表

package cn.bjut.simple.model;

    /**
     * 用户角色关联表
     */
public class SysUserRole {
    private Long userId;
    private Long roleId;

    public Long getUserId() {
        return userId;
    }

    public Long getRoleId() {
        return roleId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }
}
public class SysUserRole

角色表

package cn.bjut.simple.model;

import java.util.Date;

/**
 * 角色表
 */
public class SysRole {
    private Long id;
    private String roleName;
    private Integer enabled;
    private Long createBy;
    private Date createTime;
    private SysUser user;

    public Long getId() {
        return id;
    }

    public String getRoleName() {
        return roleName;
    }

    public Integer getEnabled() {
        return enabled;
    }

    public Long getCreateBy() {
        return createBy;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public SysUser getUser() {
        return user;
    }


    public void setId(Long id) {
        this.id = id;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public void setEnabled(Integer enabled) {
        this.enabled = enabled;
    }

    public void setCreateBy(Long createBy) {
        this.createBy = createBy;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public void setUser(SysUser user) {
        this.user = user;
    }
}
public class SysRole

权限表

package cn.bjut.simple.model;

/**
 * 权限表
 */
public class SysPrivilege {
    private Long id;
    private String privilegeName;
    private String privilegeUrl;

    public Long getId() {
        return id;
    }

    public String getPrivilegeName() {
        return privilegeName;
    }

    public String getPrivilegeUrl() {
        return privilegeUrl;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setPrivilegeName(String privilegeName) {
        this.privilegeName = privilegeName;
    }

    public void setPrivilegeUrl(String privilegeUrl) {
        this.privilegeUrl = privilegeUrl;
    }
}
public class SysPrivilege

角色与权限关联表

package cn.bjut.simple.model;

/**
 * 角色与权限关联表
 */
public class SysRolePrivilege {
    private Long roleId;
    private Long privilege;

    public Long getRoleId() {
        return roleId;
    }

    public Long getPrivilege() {
        return privilege;
    }

    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }

    public void setPrivilege(Long privilege) {
        this.privilege = privilege;
    }
}
public class SysRolePrivilege

可以参考上面创建Java实体类[JavaBean]的方式依次完成   SysUserRole 、SysRole 、SysPrivilege   、SysRolePrivilege 四个实体类的代码。

另外还可以根据本书在 第5章介绍使用MyBatis官方提供的工具 MyBatis Generator 插件 ,根据数据库表的字段信息自动生成这些实体类。

  •  MyBatis默认遵循(从SQL到JAVA)“下划线转驼峰”的命名方式。如sys_user表对应的实体类名是SysUser,数据库字段user_name对应的实体类的变量名是userName。
  •  在实体类中不要使用Java的基本数据类型,基本类型包括 byte、int、short、long、float、doubule、char、boolean。因为Java基本类型会有默认值,例如当某个实体类(对应着一个数据库表)中存在private int age;如果使用age != null进行判断,结果总会为true  会导致很多隐藏的问题。一个特殊的类型“byte[]”不是Java基本数据类型

 2.2  使用接口+XML方式

注意:接口可以配合XML使用,也可以配合注解来使用。SSM整合或SpringBoot开发,一般使用接口+通用Mapper+MyBatis3实现单表CRUD操作。

 首先,在 src/main/resources 的 cn.bjut.simple.mapper目录下创建5个表各自对应的XML映射文件,分别为 UserMapper.xml 、RoleMapper 、PrivilegeMapper 、 UserRoleMapper 和 RolePrivilegeMapper.xml 。

 然后,在 src/main/java 下面创建包 cn.bjut.simple.mapper 。接着在该包下创建XML文件对应的接口类,分别为 UserMapper.java、RoleMapper、PrivilegeMapper、 UserRoleMapper 和 RolePrivilegeMapper.java 。

 为了后续更快速的创建Mapper.xml文件,我们也可以按照如下内容添加文件模版。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
</mapper>

此处Mapper映射.xml文件的命名空间 namespace 的值需要配置成接口文件的全限定名称,例如 UserMapper接口对应的 cn.bjut.simple.mapper.UserMapper ,MyBatis内部就是通过这个值将接口和XML映射文件关联起来的。

 

准备好这几个XML映射文件后,还需要在1.3.2节中创建的 mybatis-config.xml配置文件中的 mappers元素中 配置所有的mapper文件路径。

    <mappers>
        <mapper resource="cn/bjut/simple/mapper/CountryMapper.xml"/>
        <mapper resource="cn/bjut/simple/mapper/UserMapper.xml"/>
        <mapper resource="cn/bjut/simple/mapper/RoleMapper.xml"/>
        <mapper resource="cn/bjut/simple/mapper/PrivilegeMapper.xml"/>
        <mapper resource="cn/bjut/simple/mapper/UserRoleMapper.xml"/>
        <mapper resource="cn/bjut/simple/mapper/RolePrivilegeMapper.xml"/>
    </mappers>
View Code

使用这种配置方式,最明显的缺点就是,后续如果新增了Mapper.xml映射文件,仍然需要来此处修改mybatis-config文件,不好维护操作麻烦。因此我们修改成如下配置方式,配置一个包名。

<mappers>
    <package name="cn.bjut.simple.mapper"/>
</mappers>


2.3  SELECT用法

查询单条数据

先写一个根据用户id查询用户信息的方法。在 UserMapper 接口中添加一个 selectById方法,代码如下。

    /**
     * 通过id查询用户
     *
     * @param id
     * @return
     */
     SysUser selectById(Long id);

然后在对应的UserMapper.xml中添加如下的 <resultMap>和<select>部分的代码。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.bjut.simple.mapper.UserMapper">
    <resultMap id="userMap" type="cn.bjut.simple.model.SysUser">
        <id property="id" column="id"/>
        <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>

    <select id="selectById" resultMap="userMap">     //XML中的select标签的id属性值 = “与之对应接口的方法名” 
    SELECT * FROM sys_user WHERE id = #{id}
    </select>

</mapper>

映射XML和接口的命名需要符合如下规则:

  • 标签的id属性值在任何时候都不能出现英文句号“.”,并且同一个命名空间下不能出现重复的id。
  • 接口的方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML中id的值不能重复,因而接口中的所有同名方法只会对应着XML中的同一个id的select方法。最常见的用法就是,同名方法中其中一个方法增加一个 RowBound 类型的参数用于实现分页查询

XML 标签和属性的讲解:

  • <select>:映射查询语句使用的标签。
  • id:命名空间中的唯一标识符,可用来代表这条语句。
  • resultMap:用于设置数据库返回值(列)的类型 和Java对象属性的映射关系。
  • SELECT * FROM sys_user WHERE id = #{id}是查询SQL语句。
  • #{id}:MyBatis SQL中使用预编译参数的一种方式,大括号中的id是传入的占位参数名。

在上面的 select 中,使用 resultMap 设置返回值的类型,这里的 userMap 就是上面 <resultMap> 中的 id 属性值,通过 id 引用需要的 <resultMap>

resultMap 标签用于配置 Java 对象的属性和查询结果列的对应关系,通过 resultMap 中配置的 column 和 property 可以将查询列的值映射到 type 对象的属性上

上面查询语句用到的resultMap包含的属性和标签讲解:

  • id:必填,并且唯一。在select标签中,resultMap属性的值为此处id所设置的值。
  • type:必填,用于配置查询列所映射到的Java实体类对象。
  • extends: 选填,可以配置当前的 resultMap 继承自其他的 resultMap ,属性值为继承 resultMap 的 id
  • autoMapping: 选填(true/false),该配置可以覆盖全局的 autoMappingBehavior配置。 

以上是 resultMap 的属性 resultMap 包含的所有标签如下

constructor :配置使用构造方法注入结果,包含以下两个子标签

  1. idArg:id 参数,标记结果作为 id(唯一值,可以帮助提高整体性能
  2. arg:注入到构造方法的一个普通结果

· id:一个 id 结果,标记结果作为 id(唯一值

· result:注入到 Java 对象属性的普通结果

  • association :一个复杂的类型关联,许多结果将包成这种类型
  • collection :复杂类型的集合
  • discriminator :根据结果值来决定使用哪个结果映射
  • case:基于某些值的结果映射

接着看一下id和result标签包含的属性。

id: 一个id结果,标记结果作为id主键(或唯一值)的字段(可以有多个),它们的属性值是通过setter方法注入的。

result :  注入到JAVA对象属性的普通结果。

  • column:  从数据库中得到的列名,或者列的别名。
  • property:映射到列结果的属性。可以映射一些复杂对象中的属性,例如 “address.street.number” ,这会通过“.”方式的属性嵌套赋值
  • javaType:  一个Java类的完全限定名,或通过typeAlias配置的类型别名。如果映射到 HashMap,则需要明确地指定 javaType 属性 
  • jdbcType:列对应的数据库类型。JDBC 类型仅仅需要对插入、更新、删除操作可能为空的列进行处理

接口中定义的返回值类型必须和XML映射Mapper文件中配置的resultType类型一致。否则就会因为类型不一致而抛出异常

返回值类型是由XML中的resultType(或resultMap中的type)决定的,不是由接口中写的返回值类型决定的。(本章讲XML方式,所以先忽略注解的情况)

 

查询返回多条数据:

在UserMapper接口中添加 selectAll方法,代码如下。

    /**
     * 查询全部用户
     *
     * @return
     */
     List<SysUser> selectAll();

 

在对应的 UserMapper.xml 中添加如下的<select>部分的代码。

    <select id="selectAll" resultType="cn.bjut.simple.model.SysUser">
        SELECT id,
           user_name     userName,
           user_password userPassword,
           user_email    userEmail,
           user_info     userInfo,
           head_img      headImg,
           create_time   createTime
        FROM sys_user
    </select>

 

在定义查询接口中方法的返回值时,必须注意查询SQL可能返回的结果数量。若执行的SQL返回多个结果时(>1),必须使用 List<SysUser>作为返回值。

selectById  设置结果映射使用了resultMap标签 中的id值。

selectAll      通过 resultType 直接指定了返回结果的类型。

如果使用 resultType 来设置返回结果的类型,需要在 SQL 中为所有列名和属性名不一致的列设置别名,通过设置别名使最终的查询结果列和 resultType 指定对象的属性名保持一致,进而实现自动映射

 因为数据库和 Java 中的这两种命名方式很常见,因此 MyBatis 还提供了一个全局属性 mapUnderscoreToCamelCase ,通过配置这个属性为 true 可以自动将以下画线方式命名的数据库列映射到 Java 对象的驼峰式命名属性中

    <settings>
        <!--下划线转驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--配置日志输出接口-->
        <setting name="logImpl" value="LOG4J"/>

    </settings>
mapUnderscoreToCamelCase
使用上述配置的时候,前面的 selectAll 可以改写如下
    <select id="selectAll" resultType="cn.bjut.simple.model.SysUser">
        SELECT id,
           user_name     ,
           user_password ,
           user_email    ,
           user_info     ,
           head_img      ,
           create_time
        FROM sys_user
    </select>
View Code

===============================================================================================================================

接下来通过测试用例来验证上面的两个查询。为了方便学习后面的大量测试,此处先根据第1章中的测试提取一个(后面测试类的父类)基础测试类 BaseMapperTest 

  

/**
 * 基础测试类
 */

public class BaseMapperTest {
    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init()  {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException ignore) {
            ignore.printStackTrace();
        }
    }

    public SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();

    }
}
public class BaseMapperTest

将原来的 CountryMapperTest 测试类修改如下

public  class CountryMapperTest2 extends  BaseMapperTest {

    @Test
    public void testSelectAll(){
        SqlSession sqlSession = this.getSqlSession(); //调用本类继承父类的成员方法
        try {
            List<Country> countryList = sqlSession.selectList("cn.bjut.simple.mapper.ContryMapper.selectAll");
            printCountryList(countryList); //调用本类的成员方法可以省略this关键字
        } finally {
            sqlSession.close();  //不要忘记关闭释放sqlSession
        }
    }

    private void printCountryList(List<Country> countryList){
        for(Country country : countryList){
            System.out.printf("%-4d%4s%4s\n",
                               country.getId(),
                               country.getCountryname(),
                               country.getCountrycode());
        }
    }
}
public class CountryMapperTest2 extends BaseMapperTest

另外由于在 UserMapper 中添加了一个 selectAll 方法,因此 CountryMapperTest 中的 selectAll 方法不再唯一,调用时必须带上 namespace (命名空间)。

参考 CountryMapperTest 测试类,可以模仿着编写一个 UserMapperTest 测试类,代码如下

    @Test
    public void testSelectById(){
        //获取 sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            //获取 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //调用 selectById 方法,查询 id = 1 的用户
            SysUser user = userMapper.selectById(1L);
            //user 不为空
            Assert.assertNotNull(user);
            //userName = admin
            Assert.assertEquals("admin", user.getUserName());
        } finally {
            //不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

   @Test
    public void testSelectAll(){
       SqlSession sqlSession = getSqlSession();
       try {
           UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
           List<SysUser> userList = userMapper.selectAll();
           //结果不为空
           Assert.assertTrue(userList.size() >0 );
       } finally {
           sqlSession.close();  //不要忘记关闭sqlSession
       }
    }
public class UserMapperTest extends BaseMapperTest

 // 获取 UserMapper 接口的动态代理的实现类对象

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

与上面2个SELECT单表查询不同,在实际业务中还需要多表关联查询。下面举例一些更为复杂的用法。

第一种简单的情形:根据用户id获取用户拥有的所有角色,返回的结果为角色集合,结果只有角色的信息,不包含额外的其他字段信息。

这个方法会涉及 sys_user sys_role sys_user_role 这3个表,并且该方法写在上述任何一个对应的Mapper接口中都可以。

例如,我们把这个方法写到(位于src/main/java/cn.bjut.simple.mapper包中的) UserMapper接口中,代码如下。

    /**                                              
     * 根据用户id获取角色信息                                  
     *                                               
     * @param userID                                 
     * @return                                       
     */                                              
    List<SysRole> selectRolesByUserId(Long userID);  

 在对应的 UserMapper.xml中添加如下代码。

    <select id="selectRolesByUserId" resultType="cn.bjut.simple.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>

 

虽然这个多表关联的查询中涉及了3个表,但是返回的结果只有sys_role一个表中的信息,所以直接使用 SysRole 作为返回值类型即可。

我们来编写代码对此方法进行测试。(src/main/test/java ......mapper包中 UserMapperTest增添)

    @Test
    public void testSelectRolesByUserID(){
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<SysRole>  RoleList = userMapper.selectRolesByUserId(1L);
            Assert.assertNotNull(RoleList);   //结果不为空
            Assert.assertTrue(RoleList.size() >0 );
        } finally {
            sqlSession.close();  //不要忘记关闭sqlSession
        }
    }
public void testSelectRolesByUserID()

注:如果报错,很有可能是如下图片中的select语句中‘英文逗号 ,的位置和有无造成的。

如果我希望这个查询语句同时返回SysUser表的user_name字段呢,该如何设置resultType?请参考链接文章。(不考虑嵌套的情况)

我们设置一个需求(仅为了说明用法:以第一种情形为基础,假设查询的结果不仅要包含 sys_role 中的信息,还要包含当前用户的部分信息(不考虑嵌套的情况,例如增加查询列 u.user_ name as userName 。这时 resultType 该如何设置呢 ?

方法1:就是在 SysRole 对象中直接添加 userName 属性,这样仍然使用 SysRole 作为返回值。

方法2新建扩展类(利用继承性),在扩展类中添加userName字段。

public class SysRoleExtend extends SysRole {
    private String userName;

    public String getUserName() {
        return userName;
    }

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

此时需要将映射文件中SELECT语句中的 resultType修改为:cn.bjut.example.model.SysRoleExtend。

这种方式比较适合需要少量额外字段的场景。如果需要其他表的大量字段,可以使用下面的方式3

方法3(推荐使用):新建扩展类,在扩展类中直接添加SysUser实体类的 成员变量属性字段。

package  cn.bjut.example.model;

public class SysRoleExtend extends SysRole {
    
//引用数据类型是另一个 实体类
private SysUser user; public SysUser getSysUser() { return sysUser; } public void setSysUser(SysUser sysUser) { this.sysUser = sysUser; } }

 此时需要将resultType修改为:cn.bjut.example.model.SysRoleExtend。

 在XML映射Mapper文件中

 这里设置别名的时候,使用的是 user.属性名 ,user是SysRole中刚刚增加的属性 ,userName和userEmail是SysUser对象中的属性 ,通过这种方式可以直接将值赋给user字段中的属性。

    @Test
    public void testSelectRolesByUserID2(){
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<SysRoleExtend>  RoleList = userMapper.selectRolesByUserId2(1L);
            Assert.assertNotNull(RoleList);   //结果不为空
            Assert.assertTrue(RoleList.size() >0 );
        } finally {
            sqlSession.close();  //不要忘记关闭sqlSession
        }
    }
public void testSelectRolesByUserID2

输出日志如下

 

以上是两种简单方式的介绍,在本书后续章节中还会介绍通过 resultMap 处理这种嵌套对象的方式

============================================================================

end 

posted @ 2019-07-12 19:41  Marlon康  阅读(455)  评论(0编辑  收藏  举报