MyBatis從入門到精通(五):MyBatis 注解方式的基本用法
2019-07-05 09:40 by 申城異鄉人, ... 閱讀, ... 評論, 收藏, 編輯
最近在讀劉增輝老師所著的《MyBatis從入門到精通》一書,很有收獲,于是将自己學習的過程以部落格形式輸出,如有錯誤,歡迎指正,如幫助到你,不勝榮幸!
1. @Select 注解
1.1 使用Sql語句設定别名方式
假設現在有個需求:根據id查詢角色資訊。使用注解方式該如何實作呢?
首先,在接口SysRoleMappper中添加如下方法:
@Select({"SELECT id,role_name roleName,enabled,create_by createBy,create_time createTime ","FROM sys_role ","WHERE id = #{id}"})
SysRole selectById(Long id);
上面的代碼也可以寫成如下格式:
@Select({"SELECT id,role_name roleName,enabled,create_by createBy,create_time createTime FROM sys_role WHERE id = #{id}"})
SysRole selectById(Long id);
以上2種方式都是傳遞字元串數組的形式,我們還可以用直接傳遞字元串的形式:
@Select("SELECT id,role_name roleName,enabled,create_by createBy,create_time createTime FROM sys_role WHERE id = #{id}")
SysRole selectById(Long id);
使用注解方式同樣需要考慮表字段和Java屬性字段映射的問題,使用注解方式主要有3種方式來實作。
第1種方式是通過Sql語句設定别名,上面的代碼就用的是這種方式。
1.2 使用 mapUnderscoreToCamelCase 配置方式
打開src/main/resources目錄下我們之前建立的mybatis-config.xml檔案,添加如下配置:
<settings>
<!--其他配置-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
該配置打開後,MyBatis會按照“下劃線轉駝峰“規則自動映射,即将資料庫列role_name自動轉換為屬性roleName。
此時,上面的代碼可以修改為:
@Select("SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = #{id}")
SysRole selectById(Long id);
雖然也可以寫為如下格式,但是不推薦這麼使用:
@Select("SELECT * FROM sys_role WHERE id = #{id}")
SysRole selectById(Long id);
1.3 使用 resultMap 方式
在xml中,我們使用過resultMap來配置映射:
<resultMap id="sysUserMap" type="com.zwwhnly.mybatisaction.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>
在注解方式中,有一個對應的注解@Results來配置映射:
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "roleName", column = "role_name"),
@Result(property = "enabled", column = "enabled"),
@Result(property = "createBy", column = "create_by"),
@Result(property = "createTime", column = "create_time")
})
@Select("SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = #{id}")
SysRole selectById2(Long id);
代碼簡單講解:
1)@Results注解對應着xml中的resultMap标簽
2)@Result對應着xml中的result标簽
3)
@Result(property = "id", column = "id", id = true)
對應着xml中的
<id property="id" column="id"/>
也許有人會問,我在xml中,為resultMap設定了一個id,這樣我就能複用該resultMap了,在注解方式中,支援嗎?
帶着這個疑問,讓我們來試着修改下代碼:
@Results(id = "roleResultMap", value = {
@Result(property = "id", column = "id", id = true),
@Result(property = "roleName", column = "role_name"),
@Result(property = "enabled", column = "enabled"),
@Result(property = "createBy", column = "create_by"),
@Result(property = "createTime", column = "create_time")
})
@Select("SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = #{id}")
SysRole selectById2(Long id);
結果發現代碼編譯錯誤,找不到id屬性。
按下Ctrl+B,發現@Results的源碼如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Results {
Result[] value() default {};
}
從源碼我們可以發現,這個注解沒有id屬性,難道我們每個方法上都要加上重複的映射嗎?
答案當然是否定的,不過在MyBatis 3.3.0及以前的版本中,注解定義的@Results不能共用,需要在每一個方法上都寫一遍。但是從MyBatis 3.3.1版本開始,@Results注解增加了一個id屬性,設定了id屬性後,就可以通過id屬性引用同一個@Results配置了。
看過之前幾篇部落格的讀者可能知道,我們的MyBatis 剛好使用的是3.3.0版本,是以剛好不支援設定id屬性,哈哈。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
修改MyBatis的版本為3.3.1(如果沒有設定自動導入變化的話,需要手動點下Import Changes):
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.1</version>
</dependency>
這時會發現,上面原本編譯報錯的代碼可以編譯通過了。
此時@Results的源碼如下,相比于之前的代碼,增加了id屬性:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Results {
String id() default "";
Result[] value() default {};
}
那如何引用這個@Results注解呢?請看如下代碼:
@ResultMap("roleResultMap")
@Select("SELECT * FROM sys_role")
List<SysRole> selectAll();
說明:當配合XML方式使用的時候,這裡引用的id值還可以是XML中resultMap元素的id屬性值。
為了使篇幅不至于過長,這裡不再貼出這3個方法的單元測試代碼和輸出日志,相信看過前幾篇部落格的讀者已經可以自己寫出單元測試代碼了,也可以參考文末的源碼位址下載下傳下源碼。
2. @Insert 注解
2.1 不需要傳回主鍵
和XML中的使用方式幾乎一樣,代碼如下:
@Insert({"INSERT INTO sys_role(id, role_name, enabled, create_by, create_time) ",
"VALUES (#{id},#{roleName},#{enabled},#{createBy},#{createTime,jdbcType=TIMESTAMP})"})
int insert(SysRole sysRole);
2.2 傳回自增主鍵
如果需要傳回資料庫的自增主鍵,代碼如下:
@Insert({"INSERT INTO sys_role(role_name, enabled, create_by, create_time) ",
"VALUES (#{roleName},#{enabled},#{createBy},#{createTime,jdbcType=TIMESTAMP})"})
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUseGeneratedKeys(SysRole sysRole);
和XML中的使用方式差不多,
@Options(useGeneratedKeys = true, keyProperty = "id")
等價于XML中的
useGeneratedKeys="true" keyProperty="id"
。
2.3 傳回非自增主鍵
在之前的部落格中,我們知道selectKey既支援主鍵自增的資料庫,比如MySql,也支援主鍵不自增的資料庫,如Oracle,在XML中的寫法是這樣的:
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
那麼使用注解方式該如何實作呢?代碼如下所示:
@Insert({"INSERT INTO sys_role(role_name, enabled, create_by, create_time) ",
"VALUES (#{roleName},#{enabled},#{createBy},#{createTime,jdbcType=TIMESTAMP})"})
@SelectKey(statement = "SELECT LAST_INSERT_ID()", keyColumn = "id", keyProperty = "id", resultType = Long.class, before = false)
int insertUseSelectKey(SysRole sysRole);
before = false相當于XML中的order="AFTRE",這是MySql資料庫的配置。
before = true相當于XML中的order="BEFORE",這是Oracle資料庫的配置。
注意事項:不同的資料庫statement的值會不同,上面中的值适用于MySql資料庫,使用其他類型的資料庫時要注意修改。
3. @Update 注解
和XML中的使用方式幾乎一樣,代碼如下:
@Update({"UPDATE sys_role ", "SET role_name = #{roleName},enabled = #{enabled},create_by=#{createBy}, ",
"create_time=#{createTime,jdbcType=TIMESTAMP} ", " WHERE id=#{id}"})
int updateById(SysRole sysRole);
4. @Delete 注解
和XML中的使用方式幾乎一樣,代碼如下:
@Delete("DELETE FROM sys_role WHERE id = #{id}")
int deleteById(Long id);
5. Provider注解
MyBatis提供了4種Provider注解,分别是@SelectProvider、@InsertProvider、@UpdateProvider和@DeleteProvider。
我們以@SelectProvider為例了解下Provider注解的使用方法。
首先在com.zwwhnly.mybatisaction.mapper包下建立如下類:
package com.zwwhnly.mybatisaction.mapper;
import org.apache.ibatis.jdbc.SQL;
public class SysPrivilegeProvider {
public String selectById(final Long id) {
return new SQL() {
{
SELECT("id,privilege_name,privilege_url");
FROM("sys_privilege");
WHERE("id = #{id}");
}
}.toString();
}
}
以上代碼也可以寫成如下方式:
public String selectById(final Long id) {
return "SELECT id,privilege_name,privilege_url FROM sys_privilege WHERE id = #{id}";
}
然後在接口SysPrivilegeProvider中添加如下方法:
@SelectProvider(type = SysPrivilegeProvider.class, method = "selectById")
SysPrivilege selectById(Long id);
最後在src/test/java下的com.zwwhnly.mybatisaction.mapper包下建立測試類SysPrivilegeMapperTest:
package com.zwwhnly.mybatisaction.mapper;
import com.zwwhnly.mybatisaction.model.SysPrivilege;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;
public class SysPrivilegeMapperTest extends BaseMapperTest {
@Test
public void testSelectById() {
SqlSession sqlSession = getSqlSession();
try {
SysPrivilegeMapper sysPrivilegeMapper = sqlSession.getMapper(SysPrivilegeMapper.class);
SysPrivilege sysPrivilege = sysPrivilegeMapper.selectById(1L);
Assert.assertNotNull(sysPrivilege);
Assert.assertEquals("使用者管理", sysPrivilege.getPrivilegeName());
} finally {
sqlSession.close();
}
}
}
運作測試代碼,測試通過,輸出日志如下:
DEBUG [main] - ==> Preparing: SELECT id,privilege_name,privilege_url FROM sys_privilege WHERE (id = ?)
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, privilege_name, privilege_url
TRACE [main] - <== Row: 1, 使用者管理, /users
DEBUG [main] - <== Total: 1
6. 源碼
源碼位址:https://github.com/zwwhnly/mybatis-action.git,歡迎下載下傳。
7. 參考
劉增輝《MyBatis從入門到精通》