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從入門到精通》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM