以常見用戶角色/權限控制為例,學習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從入門到精通》