• MyBatis(二)XML方式基本用法


    以常见用户角色/权限控制为例,学习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从入门到精通》

  • 相关阅读:
    正敲着代码,鼠标坏了!
    DB2 OLAP函数的使用(转)
    修剪矩形
    classpath和环境变量设置(转)
    MyEclipse断点调试JavaScript浅析(转)
    Onunload和onbeforeunload方法的异同
    db2中的coalesce函数(转)
    db2:根据TABLEID找table
    [转]DB2行列转换
    DB2删除数据时的小技巧
  • 原文地址:https://www.cnblogs.com/fantastic-clouds/p/13052891.html
Copyright © 2020-2023  润新知