Fantastic_Clouds

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

以常见用户角色/权限控制为例,学习MyBatis XML方式基本用法。

 

一、前期准备

1、创建数据库表及初始数据

(1)用户表(用户ID、用户名、密码、邮箱、简介、头像、创建时间)

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
  `user_password` varchar(50) DEFAULT NULL COMMENT '密码',
  `user_email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `user_info` text COMMENT '简介',
  `head_img` blob COMMENT '头像',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8 COMMENT='用户表';

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', 'admin@mybatis.tk', '管理员', null, '2016-04-01 17:00:58');
INSERT INTO `sys_user` VALUES ('1001', 'test', '123456', 'test@mybatis.tk', '测试用户', null, '2016-04-01 17:01:52');

(2)角色表(角色ID、角色名、有效标志、创建人、创建时间)

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  `role_name` varchar(50) DEFAULT NULL COMMENT '角色名',
  `enabled` int(11) DEFAULT NULL COMMENT '有效标志',
  `create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='角色表';

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '管理员', '1', '1', '2016-04-01 17:02:14');
INSERT INTO `sys_role` VALUES ('2', '普通用户', '1', '1', '2016-04-01 17:02:34');

(3)权限表(权限ID、权限名称、权限URL)

DROP TABLE IF EXISTS `sys_privilege`;
CREATE TABLE `sys_privilege` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
  `privilege_name` varchar(50) DEFAULT NULL COMMENT '权限名称',
  `privilege_url` varchar(50) DEFAULT NULL COMMENT '权限URL',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='权限表';

-- ----------------------------
-- Records of sys_privilege
-- ----------------------------
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');

(4)用户角色关联表(用户ID、角色ID)

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
  `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色关联表';

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

(5)角色权限关联表

-- ----------------------------
-- Table structure for sys_role_privilege
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_privilege`;
CREATE TABLE `sys_role_privilege` (
  `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
  `privilege_id` bigint(20) DEFAULT NULL COMMENT '权限ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色权限关联表';

-- ----------------------------
-- Records of sys_role_privilege
-- ----------------------------
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');

2、创建实体类

在tk.mybatis.simple.model中分别创建SysUser、SysRole、SysPrivilege、SysUserRole、SysRolePrivilege。

需要注意的是:在数据库表sys_user中,属性head_img(头像)在实际业务场景一般为图片,在Java实体类中,属性类型对应为byte[]。

3、XML方式

Mybatis从3.0开始支持使用Java的动态代理直接通过接口来调用相应的方法,不需要提供接口的实现类,更不需要在实现类中使用SqlSession以命名空间间接调用。

当接口参数大于1时,可通过参数注解@Param设置参数名字,或将使用参数封装为实体类对象,均可将参数注入对应接口中。

在数据库表及实体类创建完成的前提下,在src/main/resources的tk.mybatis.simple.mapper目录下创建5个表对应的XML文件,分别为:UserMapper.xml、RoleMapper.xml、PrivilegeMapper.xml、UserRoleMapper.xml、RolePrivilegeMapper.xml,在src/main/java的tk.mybatis.simple.mapper包中创建5个接口类:UserMapper.java、RoleMapper.java、PrivilegeMapper.java、UserRoleMapper.java、RolePrivilegeMapper.java。如下图所示:

 以UserMapper.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="tk.mybatis.simple.mapper.UserMapper">
    
</mapper>

在MyBatis中,是通过根节点<mapper>中的namespace属性将接口和XML关联起来,namespace的属性值需配置成接口的全限定名称,对UserMapper而言,则是tk.mybatis.simple.mapper.UserMapper。

参照UserMapper.xml,将其他4个XML内容补充即可。

然后,在mybatis-config.xml中配置所有的mapper:

<mappers>
     <package name="tk.mybatis.simple.mapper"/>
</mappers>

通过在mappers中配置package节点,会先查找tk.mybatis.simple.mapper包下的所有接口,循环对接口进行如下操作:

(1)判断接口对应的命名空间是否已经配置过,如果配置过就抛出异常,没有配置过就继续进行接下来的操作。

(2)加载接口对应的XML映射文件,将接口全限定名转换为路径,例如,将接口tk.mybatis.simple.mapper.UserMapper转换为tk/mybatis/simple/mapper/UserMapper.xml,以.xml为后缀搜索XML资源,如果找到就解析XML。

(3)处理接口中的注解方法。

 

二、select用法

1、通过ID查询对象

在UserMapper接口中添加selectById方法:

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

在UserMapper.xml中添加<resultMap>和<select>部分代码:

    <resultMap id="userMap" type="tk.mybatis.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">
        select * from sys_user where id = #{id}
    </select>

通过以上代码可以发现,XML中的select标签的id属性值和定义的接口方法名是一样的,如果接口方法没有和XML中的id属性值相对应,启动程序会报错。

XML和接口的命名映射规则如下:

(1)当只使用XML而不使用接口的时候,namespace的值可以设置为任意不重复的名称;

(2)标签的id属性值在任何时候都不能出现英文句号“.”,并且同一个命名空间下不能出现重复的id;

(3)接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML中的id的值不能重复,因而接口中的所有同名方法会对应着XML中的同一个id的方法。最常见用法为,同名方法中其中一个方法增加RowBound类型参数来实现分页查询。

2、resultMap标签

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

resultMap包含属性如下:

  • id:必填,唯一。在select标签中,resultMap制定的值即为此处id所设置的值。
  • type:必填,用于配置查询列所映射到的Java对象类型。
  • extends:选填,可以配置当前的resultMap继承自其他的resultMap,属性值为继承resultMap的id。
  • autoMapping:选填,可选值为true或false,用于配置是否启用非映射字段(没有在resultMap中配置的字段)的自动映射功能,改配置可以覆盖全局的autoMappingBehavior配置。

resultMap包含标签如下:

  • constructor:配置使用构造方法注入结果,包含以下两个子标签。
    • idArg:id参数,标记结果作为id(唯一值),可以帮助提高整体性能。
    • arg:注入到构造方法的一个普通结果。
  • id:一个id结果,标记结果作为id(唯一值),可以帮助提高整体性能。
  • result:注入到Java对象属性的普通结果。
  • association:一个复杂的类型关联,一般用于一对一关联。
  • collection:复杂类型的集合,一般用于一对多关联。
  • discrimination:根据结果值来决定使用哪个结果映射。
  • case:基于某些值得结果映射。

id和result标签包含的属性:

  • column:从数据库中得到的列名,或者是列的别名。
  • property:映射到列结果的属性,可以映射简单的属性,也可以映射一些复杂对象中的属性(通过“.”方式的属性嵌套赋值)。
  • javaType:一个Java类的全限定名,或一个类型别名(通过typeAlias配置或者默认的类型),如果映射到一个JavaBean,MyBatis通常可以自动判断属性的类型。如果映射到HashMap,则需要明确地制定javaType属性。
  • jdbcType:列对应的数据库类型。
  • typeHandler:使用这个属性可以覆盖默认的类型处理器。这个属性值是类的完全限定名或类型别名。

接口中定义的返回值类型必须和XML中配置的resultMap类型一致,否则会因为类型不一致而抛出异常。返回值类型是由XML中的resultMap决定的,,不是由接口中写的返回值类型决定的。

3、查询结果集

 在UserMapper接口中添加selectAll方法:

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

 在UserMapper.xml中添加如下<select>代码:

    <select id="selectAll" resultType="tk.mybatis.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>

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

注意:property属性或别名要和对象中属性的名字相同,在实际匹配时,MyBatis会先将两者都转化为大写形式,然后再判断是否相同。

由于在mybatis-configx.xml中,配置了一个全局属性mapUnderscoreToCamelCase,可以自动将以下划线命名的数据库列映射到Java对象的驼峰式命名属性中。因此,在以上<select>标签中的对数据库列所设置别名可以去掉。

4、运行单表查询程序

在src/test/java的tk.mybatis.simple.mapper包中新建测试类UserMapperTest.java,内容如下:

public class UserMapperTest extends BaseMapperTest {

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

    }

    @Test
    public void testSelectAll() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用selectAll方法,查询id = 1的用户
            List<SysUser> userList = userMapper.selectAll();
            // user不为空
            Assert.assertNotNull(userList);
            // 用户数量大于0个
            Assert.assertTrue(userList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }
}

运行以上测试方法,控制台输出如下结果:

 

 5、关联查询

(1)根据用户id获取用户,返回结果为只包含角色信息的集合

在UserMapper中添加接口方法:

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

在对应UserMapper.xml中添加<select>节点:

    <select id="selectRolesByUserId" resultType="tk.mybatis.simple.model.SysRole">
        select
            r.id,
            r.role_name roleName,
            r.enabled 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>

(2)根据用户id获取用户,除角色信息外,还包含用户名信息

在SysRole中添加对应属性:

    /**
     * 用户信息
     */
    private SysUser user;

修改XML中的selectRolesByUserId方法,通过“user.属性名”将查询的user信息直接赋值给user字段中的属性:

    <select id="selectRolesByUserId" resultType="tk.mybatis.simple.model.SysRole">
        select
            r.id,
            r.role_name roleName,
            r.enabled enabled,
            r.create_by createBy,
            r.create_time createTime,
            u.user_name as "user.userName",
            u.user_email as "user.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
    </select>

6、运行关联查询程序

在UserMapperTest.java测试类中添加测试方法:

    @Test
    public void testSelectRolesByUserId() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用testSelectRolesByUserId方法查询的用户的角色
            List<SysRole> roleList = userMapper.selectRolesByUserId(1L);
            // user不为空
            Assert.assertNotNull(roleList);
            // 用户数量大于0个
            Assert.assertTrue(roleList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }

运行以上方法,控制台输出结果如下:

 

三、insert用法

1、简单insert方法

在UserMapper中添加如下方法:

    /**
     * 新增用户
     * @param sysUser
     * @return
     */
    int insert(SysUser sysUser);

在UserMapper.xml中添加:

    <insert id="insert">
        insert into sys_user(
            id, user_name, user_password, user_email, user_info, head_img, create_time
        ) values (
            #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType = BLOB}, #{createTime, jdbcType = TIMESTAMP}
        )
    </insert>

2、insert标签

insert标签包含以下属性:

  • id:命名空间中唯一标识符,可用来代表这条语句。
  • parameterType:即将传入的语句参数的完全限定类名或别名
  • flushCache:默认为true,任何时候只要调用,都会清空一级缓存和二级缓存。
  • timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。
  • statementType:对于STATEMENT、PREPARED、CALLABLE,MyBatis会分别使用对应的statement、preparedStatement、CallableStatement,默认为PREPARED。
  • userGeneratedKeys:默认为false。如果设置为true,MyBatis会使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键。
  • keyProperty:MyBatis通过getGeneratedKeys获取主键值后将要赋值的属性名。
  • keyColumn:仅对INSERT和UPDATE有用,通过生成的键值设置表中的列名,这个设置仅在某些数据库中是必须的,当主键列不是表中的第一列时需要设置。
  • databaseId:如果设置了databaseIdProvider,MyBatis会加载所有的不带databaseId的或匹配当前databaseId的语句。

3、运行简单insert程序

在UserMapperTest.java中添加如下测试方法:

    @Test
    public void testInsert() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 创建一个user对象
            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis.tk");
            user.setUserInfo("test info");
            // 正常情况下应该插入一张图片存到byte数组中
            user.setHeadImg(new byte[] {1, 2, 3});
            user.setCreateTime(new Date());
            // 将新建的对象插入数据库中,特别注意这里的返回值result是执行的SQL影响的行数
            int result = userMapper.insert(user);
            // 只插入1条数据
            Assert.assertEquals(1, result);
            // id为null,没有给id赋值,并且没有配置回写的id的值
            Assert.assertNull(user.getId());
        } finally {
            // 为了不影响其他测试,这里选择回滚
            // 由于默认的sqlSessionFactory.openSession()是不自动提交的
            // 因此不手动执行commit也不会提交到数据库
            sqlSession.rollback();
            sqlSession.close();
        }
    }

运行得到控制台输出:

 4、使用JDBC方式返回主键自增的值

在UserMapper接口中添加insert2方法:

    /**
     * 新增用户-使用useGeneratedKeys
     * @param sysUser
     * @return
     */
    int insert2(SysUser sysUser);

在XML中新增一个insert2方法:

    <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
        insert into sys_user(
            user_name, user_password, user_email, user_info, head_img, create_time
        ) values (
            #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType = BLOB}, #{createTime, jdbcType = TIMESTAMP}
                 )
    </insert>

useGeneratedKeys设置为true后,MyBatis会使用JDBC的getGeneratedKeys方法取出由数据库内部生成的主键,并将其赋值给keyProperty配置的id属性。当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置keyColumn属性,按顺序指定数据库的列,这里列的值会和keyProperty配置的属性一一对应。

下面通过测试方法来验证以上内容:

    @Test
    public void testInsert2() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 创建一个user对象
            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis.tk");
            user.setUserInfo("test info");
            user.setHeadImg(new byte[] {1, 2, 3});
            user.setCreateTime(new Date());
            int result = userMapper.insert2(user);
            // 只插入1条数据
            Assert.assertEquals(1, result);
            Assert.assertNotNull(user.getId());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

 5、使用selectKey返回主键的值

有些数据库不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给id,再将数据插入数据库,这种情况需要使用<selectKey>标签来获取主键的值。

在接口和XML中分别添加insert3:

    /**
     * 新增用户-使用selecctKey方式
     * @param sysUser
     * @return
     */
    int insert3(SysUser sysUser);
    <insert id="insert3">
        insert into sys_user(
            user_name, user_password, user_email, user_info, head_img, create_time
        ) values (
            #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType = BLOB}, #{createTime, jdbcType = TIMESTAMP}
        )
        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            select last_insert_id()
        </selectKey>
    </insert>

在MySQL数据库中,order属性设置的值是AFTER,因为当前记录的主键值在insert语句执行成功后才能获取到。而在Oracle数据库中,order的值要设置为BEFORE,因为Oracle中需要先从序列中获取值,然后将值作为主键插入到数据库中。

 

四、update用法

在UserMapper接口中添加updateById方法:

    /**
     * 根据主键更新
     * @param sysUser
     * @return
     */
    int updateById(SysUser sysUser);

在UserMapper.xml中添加<update>标签:

    <update id="updateById">
        update sys_user
        set user_name = #{userName},
            user_password = #{userPassword},
            user_email = #{userEmail},
            user_info = #{userInfo},
            head_img = #{headImg, jdbcType = BLOB},
            create_time = #{createTime, jdbcType = TIMESTAMP}
        where id = #{id}
    </update>

在UserMapperTest中添加测试方法:

    @Test
    public void testUpdateById() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 从数据库查询1个user对象
            SysUser user = userMapper.selectById(1L);
            // 当前userName为admin
            Assert.assertEquals("admin", user.getUserName());
            // 修改用户名
            user.setUserName("admin_test");
            // 修改邮箱
            user.setUserEmail("test@mybatis.tk");
            // 更新数据,特别注意,这里的返回值result是执行的SQL影响的行数
            int result = userMapper.updateById(user);
            // 只更新1条数据
            Assert.assertEquals(1, result);
            // 根据当前id查询修改后的数据
            user = userMapper.selectById(1L);
            // 修改后的名字是admin_test
            Assert.assertEquals("admin_test", user.getUserName());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

运行程序验证:

 

 五、delete用法

在UserMapper中添加deleteById方法:

    /**
     * 通过主键删除
     * @param id
     * @return
     */
    int deleteById(Long id);

在UserMapper.xml中添加<delete>标签:

    <delete id="deleteById">
        delete from sys_user where id = #{id}
    </delete>

在UserMapperTest中添加测试方法:

    @Test
    public void testDeleteById() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 从数据库查询出1个user对象,根据id=1查询
            SysUser user1 = userMapper.selectById(1L);
            // 现在还能查询出user对象
            Assert.assertNotNull(user1);
            // 调用方法删除
            Assert.assertEquals(1, userMapper.deleteById(1L));
            // 再次查询,这时应该没有值,为null
            Assert.assertNull(userMapper.selectById(1L));

            // 使用SysUser参数再进行一次测试,根据id = 1001查询
            SysUser user2 = userMapper.selectById(1001L);
            // 现在还能查询出user对象
            Assert.assertNotNull(user2);
            // 调用方法删除
            Assert.assertEquals(1, userMapper.deleteById(user2));
            // 再次查询,这时应该没有值,为null
            Assert.assertNull(userMapper.selectById(1001L));
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

运行程序验证:

 

 六、多个接口参数用法

对于Mapper接口参数包含多个的情况,可以将多个参数合并到一个JavaBean中,或者使用Map类型作为参数、使用@param注解。

对于某些查询而言,查询参数并不适合封装成一个JavaBean,因此将多个参数合并到JavaBean的用法只适用于特定场景。

在使用Map类型作为参数的接口方法,key-value需手动创建并赋值。

以@Param注解传参为例,在UserMapper中添加以下方法:

    /**
     * 根据用户id和角色的enabled状态获取用户的角色
     * @param userId
     * @param enabled
     * @return
     */
    List<SysRole> selectRolesByUserIdAndRoleEnabled(Long userId, Integer enabled);

在XML中添加对应的<select>标签:

    <select id="selectRolesByUserIdAndRoleEnabled" resultType="tk.mybatis.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} and r.enabled = #{enabled}
    </select>

新增对应测试方法:

    @Test
    public void testSelectRolesByUserIdAndRoleEnabled() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用selectRolesByUserIdAndRoleEnabled方法查询用户的角色
            List<SysRole> userList = userMapper.selectRolesByUserIdAndRoleEnabled(1L, 1);
            // 结果不为空
            Assert.assertNotNull(userList);
            // 角色的数量大于0
            Assert.assertTrue(userList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }

运行程序,控制台显示如下输出:

 在新增方法中,使用了两个参数userId、enabled,但是从以上错误日志可以看出,可用参数只有0、1、param1、param2,并无所需的userId和enabled。

按照提示,可以将XML中参数替换为#{0}、#{1}或者#{param1}、#{param2},但是在参数数量、名称或位置调整时,不易于维护。

此时,对接口方法做如下修改,参数以@param进行注解,并将其value与XML中传入参数相对应:

    /**
     * 根据用户id和角色的enabled状态获取用户的角色
     * @param userId
     * @param enabled
     * @return
     */
    List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);

再运行测试方法,控制显示如下:

 给参数配置@param注解后,MyBatis会自动将参数封装成Map类型,并传入SQL中使用。

 

以上内容整理自《MyBatis从入门到精通》

posted on 2020-06-06 22:35  Fantastic_Clouds  阅读(2254)  评论(1编辑  收藏  举报