Mybatis註解用法

MyBatis(八) mybatis註解

一、mybatis簡單註解


 
  • @Insert : 插入sql , 和xml insert sql語法完全一樣@Select : 查詢sql, 和xml select sql語法完全一樣
  • @Update : 更新sql, 和xml update sql語法完全一樣
  • @Delete : 刪除sql, 和xml delete sql語法完全一樣
  • @Param : 入參
  • @Results : 設置結果集合@Result : 結果
  • @ResultMap : 引用結果集合
  • @SelectKey : 獲取最新插入id

less

具體使用:

1、@Select、@Results、@Result


 
  • /**
  • * 查詢所有
  • * @return Employee泛型集合
  • */
  • @Select("select * from t_emp")
  • @Results(id = "empMap",value = {
  • @Result(column = "emp_id",property = "empId",id = true),
  • @Result(column = "emp_name",property = "empName"),
  • @Result(column = "emp_tel",property = "empTel"),
  • @Result(column = "emp_education",property = "empEducation"),
  • @Result(column = "emp_birthday",property = "empBirthday"),
  • @Result(column = "fk_dept_id",property = "dept"
  • ,one = @One(select = "com.yingside.dao.DeptMapper.getById",
  • fetchType = FetchType.LAZY))
  • })
  • List<Employee> getAll();

java

2、@Delete、@Param、@ResultMap


 
  • /**
  • * 根據id查詢員工
  • * @param empId 員工主鍵id
  • * @return 員工對象
  • */
  • @Select("select * from t_emp where emp_id=#{empId}")
  • @ResultMap(value="empMap")
  • Employee getById(@Param("empId") Integer empId);

java

3、@Insert、@SelectKey


 
  • /**
  • * 插入新員工信息,並將最新id放入到員工對象在
  • * @param record 新員工對象
  • * @return 插入成功 1 失敗 0
  • */
  • @Insert("insert into t_emp (emp_id, emp_name, emp_tel, " +
  • " emp_education, emp_birthday, fk_dept_id" +
  • " )" +
  • " values (#{empId}, #{empName}, #{empTel}, " +
  • " #{empEducation}, #{empBirthday}, #{fkDeptId}" +
  • " )")
  • @SelectKey(before = false,keyColumn = "emp_id",keyProperty = "empId",
  • statement = "select last_insert_id()",resultType = Integer.class)
  • int insert(Employee record);

java

4、@Delete、@Param


 
  • /**
  • * 根據員工id刪除員工
  • * @param empId 員工主鍵id
  • * @return 刪除成功 1 失敗 0
  • */
  • @Delete("delete from t_emp where emp_id=#{empId}")
  • int deleteByPrimaryKey(@Param("empId") Integer empId);

java

5、@Update


 
  • /**
  • * 更新員工信息
  • * @param record 員工對象
  • * @return 更新成功 1 失敗 0
  • */
  • @Update("update t_emp" +
  • " set emp_name = #{empName,jdbcType=VARCHAR}," +
  • " emp_tel = #{empTel,jdbcType=VARCHAR}," +
  • " emp_education = #{empEducation,jdbcType=VARCHAR}," +
  • " emp_birthday = #{empBirthday,jdbcType=DATE}," +
  • " fk_dept_id = #{fkDeptId,jdbcType=INTEGER}" +
  • " where emp_id = #{empId,jdbcType=INTEGER}")
  • int update(Employee record);

java

當然最後別忘記了,寫完這些之後,在覈心配置文件中要把映射文件給加上,之前使用的時候,找尋的是resouce xml的資源路徑,現在由於使用了註解,就只有接口文件了,所有配置相應的要做一個簡單的修改


 
  • <mappers>
  • <mapper class="com.yingside.dao.EmployeeMapper" />
  • </mappers>

二、動態SQL

1、簡單處理,直接使用<script>腳本


 
  • /**
  • * script實現動態sql更新員工信息
  • * @param record 員工對象
  • * @return 更新成功 1 失敗 0
  • */
  • @Update("<script>" +
  • "update t_emp" +
  • " <set >" +
  • " <if test=\"empName != null\" >" +
  • " emp_name = #{empName,jdbcType=VARCHAR},\n" +
  • " </if>" +
  • " <if test=\"empTel != null\" >" +
  • " emp_tel = #{empTel,jdbcType=VARCHAR}," +
  • " </if>" +
  • " <if test=\"empEducation != null\" >" +
  • " emp_education = #{empEducation,jdbcType=VARCHAR}," +
  • " </if>" +
  • " <if test=\"empBirthday != null\" >" +
  • " emp_birthday = #{empBirthday,jdbcType=DATE}," +
  • " </if>" +
  • " <if test=\"fkDeptId != null\" >" +
  • " fk_dept_id = #{fkDeptId,jdbcType=INTEGER}," +
  • " </if>" +
  • " </set>" +
  • " where emp_id = #{empId,jdbcType=INTEGER}" +
  • "</script>")
  • int updateByPrimaryKeySelective(Employee record);

java

2、使用Provider註解標識

增刪改查,每一個都有一個對應的Provider註解標識


 
  • @Insert :@InsertProvider
  • @Select :@SelectProvider
  • @Update :@UpdateProvider
  • @Delete :@DeleteProvider

java

使用:

2.1、創建Provider類


 
  • public class EmployeeProvider {
  • public String updateSQL(Employee emp) {
  • return new SQL() {
  • {
  • UPDATE("t_emp");
  • if (emp.getEmpName() != null) {
  • SET("emp_name = #{empName}");
  • }
  • if (emp.getEmpTel() != null) {
  • SET("emp_tel = #{empTel}");
  • }
  • if (emp.getEmpEducation() != null) {
  • SET("emp_education = #{empEducation}");
  • }
  • if (emp.getEmpBirthday() != null) {
  • SET("emp_birthday = #{empBirthday}");
  • }
  • if (emp.getFkDeptId() != null) {
  • SET("fk_dept_id = #{fkDeptId}");
  • }
  • WHERE("emp_id = #{empId}");
  • }
  • }.toString();
  • }
  • }

java

這裏使用的Provider的一些關鍵字

掌握最重要的一點,Provider其實就是要返回一個SQL字符串 只不過用了一些關鍵字做格式化而已,其實不使用也可以 完全可以使用String字符串拼接SQL語句,當然複雜的語句還是建議使用StringBuilder或者StringBuffer拼接

2.2、註解使用Provider類


 
  • @UpdateProvider(type = EmployeeProvider.class, method = "updateSQL")
int updateBySelectiveProvider(Employee record);

三、註解使用多表關聯查詢

1、使用子查詢方式

1.1、多對一或者一對一中的一端寫法 @One

這種查詢方式和之前在xml中介紹的第二種方式一樣,相當於就是一個子查詢先查詢員工,再根據員工查詢出來的部門外鍵查詢部門信息,最後再把查詢出來的信息放入到Employee對象中的Dept屬性中

EmployeeMapper.java 接口:


 
  • /**
  • * 查詢所有
  • * @return Employee泛型集合
  • */
  • @Select("select * from t_emp")
  • @Results(id = "empMap",value = {
  • @Result(column = "emp_id",property = "empId",id = true),
  • @Result(column = "emp_name",property = "empName"),
  • @Result(column = "emp_tel",property = "empTel"),
  • @Result(column = "emp_education",property = "empEducation"),
  • @Result(column = "emp_birthday",property = "empBirthday"),
  • @Result(column = "fk_dept_id",property = "dept"
  • ,one = @One(select = "com.yingside.dao.DeptMapper.getById",
  • fetchType = FetchType.LAZY))
  • })
  • List<Employee> getAll();

java

DeptMapper.java 接口:


 
  • public interface DeptMapper {
  • @Results(id="deptMap",value = {
  • @Result(column = "dept_id",property = "deptId",id = true),
  • @Result(column = "dept_name",property = "deptName"),
  • @Result(column = "dept_info",property = "deptInfo"),
  • @Result(column = "dept_createDate",property = "deptCreatedate")
  • })
  • @Select("select * from t_dept where dept_id=#{deptId}")
  • Dept getById(@Param("deptId") Integer deptId);
  • }

java

1.2、一對多或者多對多中的多端寫法 @Many

通過子查詢,先查詢部門信息再通過部門主鍵,在員工外鍵表中查詢和部門相關聯的員工信息

DeptMapper.java 接口:


 
  • public interface DeptMapper {
  • @Results(id="deptMap",value = {
  • @Result(column = "dept_id",property = "deptId",id = true),
  • @Result(column = "dept_name",property = "deptName"),
  • @Result(column = "dept_info",property = "deptInfo"),
  • @Result(column = "dept_createDate",property = "deptCreatedate"),
  • @Result(column = "dept_id",property = "employeeList"
  • ,many = @Many(select = "com.yingside.dao.EmployeeMapper.getEmpsByDeptId",
  • fetchType = FetchType.LAZY))
  • })
  • @Select("select * from t_dept where dept_id=#{deptId}")
  • Dept getById(@Param("deptId") Integer deptId);
  • }

java

EmployeeMapper.java 接口:


 
  • public interface EmployeeMapper {
  • //......其他代碼省略
  • /**
  • * 根據部門id查詢部門下所有員工
  • * @param fkDeptId 部門id
  • * @return 員工的泛型集合
  • */
  • @Select("select * from t_emp where fk_dept_id=#{fkDeptId}")
  • //@ResultMap("empMap")
  • List<Employee> getEmpsByDeptId(@Param("fkDeptId") int fkDeptId);
  • }

java

2、N+1問題

注意:像上面這種通過子查詢的方式實現關聯查詢,最好就只是查詢一個方向就行了,意思是,要麼通過員工查詢部門,要麼就通過部門查詢員工。不要兩個都寫。上面的例子只是簡單說明一端多端的寫法。如果兩個都寫的話,就會引起循環引用的問題,查員工的時候發現要子查詢部門,查了部門發現又要查員工......就會報出下面的錯誤:


 
  • java.lang.StackOverflowError

所以,最佳實踐:儘量不要出現這種情況的互相引用。這種子查詢的方式,建議是在必須使用懶加載的情況下使用。如果一般情況的多表查詢,還是使用表的級聯分頁查詢,inner,left,right join等

3、最佳實踐-註解與xml結合使用

3.1、xml文件配置resultMap,這樣方便多個接口調用

3.2、配置映射

3.3、註解代碼

3.3.1、簡單的註解代碼


 
  • /**
  • * 通過級聯查詢查詢員工信息
  • * @return 員工的泛型集合
  • */
  • @Select("select * from t_emp join t_dept on t_emp.fk_dept_id = t_dept.dept_id")
  • @ResultMap("com.yingside.mapper.EmployeeMapper.employeeMap")
  • List<Employee> getAllJoin();

java

注意這裏@ResultMap的值是xml文件的地址

3.3.2、複雜的代碼可以結合使用Provider

EmployeeProvider.java


 
  • package com.yingside.provider;
  • import com.yingside.po.Employee;
  • import org.apache.ibatis.jdbc.SQL;
  • import java.util.Map;
  • public class EmployeeProvider {
  • //......其他代碼省略
  • public String selectListProvider(Map<String,Object> map){
  • return new SQL(){
  • {
  • SELECT(" t_emp.emp_id," +
  • " t_emp.emp_name," +
  • " t_emp.emp_tel," +
  • " t_emp.emp_education," +
  • " t_emp.emp_birthday," +
  • " t_dept.dept_id," +
  • " t_dept.dept_name," +
  • " t_dept.dept_info," +
  • " t_dept.dept_createDate");
  • FROM("t_emp");
  • LEFT_OUTER_JOIN("t_dept on t_emp.fk_dept_id = t_dept.dept_id");
  • if (map.get("empName") != null){
  • AND().WHERE("t_emp.emp_name like concat('%',#{empName},'%')");
  • }
  • if (map.get("empTel") != null){
  • AND().WHERE("t_emp.emp_tel like concat('%',#{empTel},'%')");
  • }
  • if (map.get("deptId") != null){
  • AND().WHERE("t_dept.dept_id=#{deptId}");
  • }
  • }}.toString();
  • }
  • }

java

EmployeeDao.java


 
  • /**
  • * 通過級聯查詢動態sql Provider查詢員工新
  • * @param map 鍵值對的參數
  • * @return 員工的泛型集合
  • */
  • @SelectProvider(type = EmployeeProvider.class, method = "selectListProvider")
  • @ResultMap("com.yingside.mapper.EmployeeMapper.employeeMap")
  • List<Employee> getAllJoinProvider(Map<String,Object> map);

java

測試


 
  • @Test
  • public void testGetAllJoinProvider(){
  • EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
  • Map<String,Object> map = new HashMap<>();
  • map.put("empName","公");
  • map.put("deptId",1);
  • List<Employee> all = mapper.getAllJoinProvider(map);
  • log.info(all);
  • sqlSession.commit();
  • }

java

四、Mybatis全部註解列表

註解 目標 相對應的 XML 描述
@CacheNamespace <cache> 爲給定的命名空間 (比如類) 配置緩存。 屬性:implemetation,eviction, flushInterval,size 和 readWrite。
@CacheNamespaceRef <cacheRef> 參照另外一個命名空間的緩存來使用。 屬性:value,應該是一個名空間的字 符串值(也就是類的完全限定名) 。
@ConstructorArgs 方法 <constructor> 收集一組結果傳遞給一個劫奪對象的 構造方法。屬性:value,是形式參數 的數組。
@Arg 方法 <arg>``<idArg> 單 獨 的 構 造 方 法 參 數 , 是 ConstructorArgs 集合的一部分。屬性: id,column,javaType,typeHandler。 id 屬性是布爾值, 來標識用於比較的屬 性,和XML 元素相似。
@TypeDiscriminator 方法 <discriminator> 一組實例值被用來決定結果映射的表 現。 屬性: column, javaType, jdbcType, typeHandler,cases。cases 屬性就是實 例的數組。
@Case 方法 <case> 單獨實例的值和它對應的映射。屬性: value,type,results。Results 屬性是結 果數組,因此這個註解和實際的 ResultMap 很相似,由下面的 Results 註解指定。
@Results 方法 <resultMap> 結果映射的列表, 包含了一個特別結果 列如何被映射到屬性或字段的詳情。 屬 性:value, id。value 屬性是 Result 註解的數組。 The id attribute is the name of the result mapping.
@Result 方法 <result>``<id> 在列和屬性或字段之間的單獨結果映 射。屬 性:id,column, property, javaType ,jdbcType ,type Handler, one,many。id 屬性是一個布爾值,表 示了應該被用於比較(和在 XML 映射 中的相似)的屬性。one 屬性是單 獨 的 聯 系, 和 <association> 相 似 , 而 many 屬 性 是 對 集 合 而 言 的 , 和 <collection>相似。 它們這樣命名是爲了 避免名稱衝突。
@One 方法 <association> 複雜類型的單獨屬性值映射。屬性: select,已映射語句(也就是映射器方 法)的完全限定名,它可以加載合適類 型的實例。注意:聯合映射在註解 API 中是不支持的。這是因爲 Java 註解的 限制,不允許循環引用。 fetchType, which supersedes the global configuration parameterlazyLoadingEnabled for this mapping.
@Many 方法 <collection> A mapping to a collection property of a complex type. Attributes: select, which is the fully qualified name of a mapped statement (i.e. mapper method) that can load a collection of instances of the appropriate types,fetchType, which supersedes the global configuration parameterlazyLoadingEnabled for this mapping. NOTE You will notice that join mapping is not supported via the Annotations API. This is due to the limitation in Java Annotations that does not allow for circular references.
@MapKey 方法   復 雜 類 型 的 集合 屬 性 映射 。 屬 性 : select,是映射語句(也就是映射器方 法)的完全限定名,它可以加載合適類 型的一組實例。注意:聯合映射在 Java 註解中是不支持的。這是因爲 Java 注 解的限制,不允許循環引用。
@Options 方法 映射語句的屬性 這個註解提供訪問交換和配置選項的 寬廣範圍, 它們通常在映射語句上作爲 屬性出現。 而不是將每條語句註解變復 雜,Options 註解提供連貫清晰的方式 來訪問它們。屬性:useCache=true , flushCache=FlushCachePolicy.DEFAULT , resultSetType=FORWARD_ONLY , statementType=PREPARED , fetchSize=-1 , , timeout=-1 useGeneratedKeys=false , keyProperty=”id” , keyColumn=”” , resultSets=””。 理解 Java 註解是很 重要的,因爲沒有辦法來指定“null” 作爲值。因此,一旦你使用了 Options 註解,語句就受所有默認值的支配。要 注意什麼樣的默認值來避免不期望的 行爲。   @Insert``@Update``@Delete``@Select 方法 <insert>``<update>``<delete>``<select> 這些註解中的每一個代表了執行的真 實 SQL。 它們每一個都使用字符串數組 (或單獨的字符串)。如果傳遞的是字 符串數組, 它們由每個分隔它們的單獨 空間串聯起來。這就當用 Java 代碼構 建 SQL 時避免了“丟失空間”的問題。 然而,如果你喜歡,也歡迎你串聯單獨 的字符串。屬性:value,這是字符串 數組用來組成單獨的 SQL 語句。   @InsertProvider``@UpdateProvider``@DeleteProvider``@SelectProvider   方法 <insert>``<update>``<delete>``<select> 這些可選的 SQL 註解允許你指定一個 類名和一個方法在執行時來返回運行 允許創建動態 的 SQL。 基於執行的映射語句, MyBatis 會實例化這個類,然後執行由 provider 指定的方法. 該方法可以有選擇地接受參數對象.(In MyBatis 3.4 or later, it’s allow multiple parameters) 屬性: type,method。type 屬性是類。method 屬性是方法名。 注意: 這節之後是對 類的 討論,它可以幫助你以乾淨,容於閱讀 的方式來構建動態 SQL。
@Param Parameter   如果你的映射器的方法需要多個參數, 這個註解可以被應用於映射器的方法 參數來給每個參數一個名字。否則,多 參數將會以它們的順序位置來被命名 (不包括任何 RowBounds 參數) 比如。 #{param1} , #{param2} 等 , 這 是 默 認 的 。 使 用 @Param(“person”),參數應該被命名爲 #{person}。
@SelectKey 方法 <selectKey> This annotation duplicates the functionality for methods annotated with @Insert, @InsertProvider, @Update or@UpdateProvider. It is ignored for other methods. If you specify a@SelectKey annotation, then MyBatis will ignore any generated key properties set via the @Options annotation, or configuration properties. Attributes: statement an array of strings which is the SQL statement to execute, keyProperty which is the property of the parameter object that will be updated with the new value, before which must be either true orfalse to denote if the SQL statement should be executed before or after the insert, resultType which is the Java type of the keyProperty, andstatementType=PREPARED.
@ResultMap 方法   This annotation is used to provide the id of a <resultMap> element in an XML mapper to a @Select or @SelectProvider annotation. This allows annotated selects to reuse resultmaps that are defined in XML. This annotation will override any @Results or @ConstructorArgs annotation if both are specified on an annotated select.
@ResultType 方法   This annotation is used when using a result handler. In that case, the return type is void so MyBatis must have a way to determine the type of object to construct for each row. If there is an XML result map, use the @ResultMap annotation. If the result type is specified in XML on the<select> element, then no other annotation is necessary. In other cases, use this annotation. For example, if a @Select annotated method will use a result handler, the return type must be void and this annotation (or @ResultMap) is required. This annotation is ignored unless the method return type is void.
@Flush 方法   If this annotation is used, it can be called theSqlSession#flushStatements() via method defined at a Mapper interface.(MyBatis 3.3 or above)

本文鏈接:http://www.yanhongzhi.com/post/mybatis-annotation.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章