欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis中動態(tài)SQL語句@Provider的用法

 更新時間:2023年06月22日 09:54:26   作者:大飯盒  
本文主要介紹了MyBatis中動態(tài)SQL語句@Provider的用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

Mybatis里的動態(tài)SQL,估計用到的同學不是很多,畢竟在xml文件中定義sql語句的方式,已經可以滿足絕大部分的開發(fā)需求,方便又簡單。沒有痛點,也就少了動力。這一章就來聊聊這塊,對于有代碼潔癖的人來說,還是很賞心悅目的。

四個注解

@Provider系列的注解有四個:

  • @SelectProvider,被定義用來提供查詢方法的SQL;
  • @UpdateProvider,被定義用來提供更新方法的SQL;
  • @DeleteProvider,被定義用來提供刪除方法的SQL;
  • @InsertProvider,被定義用來提供保存方法的SQL;

官方例子

public interface UserMapper {
  // 保存用戶數據
  @InsertProvider(type = SqlProvider.class, method = "insert")
  void insert(User user);
  public static class SqlProvider {
    // 對應@InsertProvider注解里的method,返回對應sql
    public static String insert() {
      return "INSERT INTO users (id, name) VALUES(#{id}, #{name})";
    }
  }
}

序列圖

此章節(jié)主要源碼都在ProviderSqlSource里。

源碼

這里介紹的源碼不多,主要是兩個部分

sql拼接;

  • 反射執(zhí)行provider方法;

sql拼接

sql拼接,主要依賴AbstractSQL里的靜態(tài)方法,下面講一下update語句。

  List<String> sets = new ArrayList<>();
  List<String> tables = new ArrayList<>();
  List<String> where = new ArrayList<>();
  public T UPDATE(String table) {
    // 指定類型為update
    sql().statementType = SQLStatement.StatementType.UPDATE;
    // 設定表名,tables集合添加元素
    sql().tables.add(table);
    // 返回當前sqlBuilder對象
    return getSelf();
  }
    private String updateSQL(SafeAppendable builder) {
       // 拼接 UPDATE [table_name]
      sqlClause(builder, "UPDATE", tables, "", "", "");
      joins(builder);
      // 拼接sets集合
      sqlClause(builder, "SET", sets, "", "", ", ");
      // 拼接where條件集合
      sqlClause(builder, "WHERE", where, "(", ")", " AND ");
      // 拼接限定條件
      limitingRowsStrategy.appendClause(builder, null, limit);
      return builder.toString();
    }

注意:sql拼接是按照一定順序的,tables -> sets -> where,就算是我們在代碼里,刻意打亂順序,也沒有影響,比如:

 WHERE("md5 = #{md5}");
 SET("update_time = NOW()");
 UPDATE(tableName);

其實是可以的,畢竟Provider本質上,就是提供了待執(zhí)行的sql預處理語句??垂俜降睦?,其實就沒有使用拼接,在后面的例子里,如果不進行參數判空,可以寫成這樣:

public String updateStatus() {
    return "UPDATE tb_image SET update_time = NOW(), status = ? WHERE (md5 = ?) AND (status = ?)";
}

反射執(zhí)行provider方法

  private String invokeProviderMethod(Object... args) throws Exception {
    Object targetObject = null;
    if (!Modifier.isStatic(providerMethod.getModifiers())) {
      // 如果是非靜態(tài)方法,則需要一個類實例
      targetObject = providerType.getDeclaredConstructor().newInstance();
    }
    // 反射執(zhí)行@Provider里指定的方法
    CharSequence sql = (CharSequence) providerMethod.invoke(targetObject, args);
    // 返回sql語句
    return sql != null ? sql.toString() : null;
  }

這里返回的sql語句,是基于JDBC預處理語法的字符串,例如UPDATE tb_image SET update_time = NOW(), status = ? WHERE (md5 = ?) AND (status = ?)

參數是怎么處理的

CharSequence sql = (CharSequence) providerMethod.invoke(targetObject, args);這一行代碼里,指定了方法參數【args】,首先說明,provider方法里的參數,都來自于Mapper里的方法參數值,從params里獲取對應參數名稱的值,寫入到args;

  private Object[] extractProviderMethodArguments(Map<String, Object> params, String[] argumentNames) {
    Object[] args = new Object[argumentNames.length];
    for (int i = 0; i < args.length; i++) {
      if (providerContextIndex != null && providerContextIndex == i) {
        args[i] = providerContext;
      } else {
        // 關鍵就是這一句,從params里獲取對應參數名稱的值,寫入到args;
        args[i] = params.get(argumentNames[i]);
      }
    }
    return args;
  }

方法參數介紹

  • params:Mapper里對應方法的所有參數;
  • argumentNames:Provider里方法的參數名稱;

這是下面例子里的參數處理結果

我的例子

provider

注意provider里方法的參數,可以和mapper參數一致,也可以缺失幾個。引用mapper的參數,主要是為了進行邏輯分支判定。

public class ImageDynamicProvider {
    /**
     * 圖片更新
     *
     * @return sql
     */
    public String updateStatus(Integer newStatus, Integer oldStatus) {
        Table table = ImageInfo.class.getAnnotation(Table.class);
        String tableName = table.name();
        return new SQL() {
            {
                UPDATE(tableName);
                SET("update_time = NOW()");
                // 判定是否需要更新狀態(tài)
                if (newStatus != null) {
                    SET("status = #{newStatus}");
                }
                WHERE("md5 = #{md5}");
                // 判定是否需要此條件
                if (oldStatus != null) {
                    AND().WHERE("status = #{oldStatus}");
                }
            }
        }.toString();
    }
}

引用Provider

在Mapper對應的方法上面,根據具體類型,選擇注解。此處是更新語句,所以使用@UpdateProvider,參數提供了具體的類和方法,供后續(xù)執(zhí)行反射方法。

    /**
     * 更新狀態(tài)
     *
     * @param md5 圖片摘要信息
     */
    @UpdateProvider(value = ImageDynamicProvider.class, method = "updateStatus")
    int updateStatusByProvider(@Param(value = "md5") String md5,
                               @Param(value = "oldStatus") int oldStatus,
                               @Param(value = "newStatus") int newStatus);

測試用例

    @Test
    public void provider() {
        imageInfoMapper.updateStatusByProvider( "6e705a7733ac5gbwopmp02", 50, 199);
    }

輸出

==>  Preparing: UPDATE tb_image SET update_time = NOW(), status = ? WHERE (md5 = ?) AND (status = ?)
==> Parameters: 199(Integer), 6e705a7733ac5gbwopmp02(String), 50(Integer)
<==    Updates: 1

小問題

如果既有Provider,也有xml方法映射。就是說我們定義了@Provider注解,又在xml中寫了mapper方法的映射sql語句,這種場景,Mybatis在啟動時就會報錯。

nested exception is java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.essay.dao.ImageInfoMapper.updateStatusProvider

到此這篇關于MyBatis中動態(tài)SQL語句@Provider的用法的文章就介紹到這了,更多相關MyBatis 動態(tài)SQL @Provider內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java 判斷二進制文件的方法

    java 判斷二進制文件的方法

    這篇文章主要介紹了java 判斷二進制文件的方法的相關資料,這里提供實例來實現判斷文件是否問二進制文件,希望能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Java Eclipse中實現快速替換變量

    Java Eclipse中實現快速替換變量

    這篇文章主要介紹了Java Eclipse中實現快速替換變量,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • RestTemplate未使用線程池問題的解決方法

    RestTemplate未使用線程池問題的解決方法

    今天給大家?guī)淼氖顷P于Springboot的相關知識,文章圍繞著RestTemplate未使用線程池展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java微信公眾平臺開發(fā)(5) 文本及圖文消息回復的實現

    Java微信公眾平臺開發(fā)(5) 文本及圖文消息回復的實現

    這篇文章主要為大家詳細介紹了Java微信公眾平臺開發(fā)第五步,回文本及圖文消息回復的實現代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Spring boot JPA實現分頁和枚舉轉換代碼示例

    Spring boot JPA實現分頁和枚舉轉換代碼示例

    這篇文章主要介紹了Spring boot JPA實現分頁和枚舉轉換代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • 使用eclipse + maven一步步搭建SSM框架教程詳解

    使用eclipse + maven一步步搭建SSM框架教程詳解

    SSM(Spring+SpringMVC+MyBatis)框架集由Spring、SpringMVC、MyBatis三個開源框架整合而成,常作為數據源較簡單的web項目的框架.這篇文章主要介紹了eclipse + maven搭建SSM框架 ,需要的朋友可以參考下
    2017-11-11
  • Automapper實現自動映射的實例代碼

    Automapper實現自動映射的實例代碼

    這篇文章主要介紹了Automapper實現自動映射的實例代碼,需要的朋友可以參考下
    2017-09-09
  • ReentrantLock獲取鎖釋放鎖的流程示例分析

    ReentrantLock獲取鎖釋放鎖的流程示例分析

    這篇文章主要為大家介紹了ReentrantLock獲取鎖釋放鎖的流程示例分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • java回溯算法解數獨問題

    java回溯算法解數獨問題

    這篇文章主要為大家詳細介紹了java回溯算法解數獨問題,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Spring MVC請求參數的深入解析

    Spring MVC請求參數的深入解析

    這篇文章主要給大家介紹了關于Spring MVC請求參數解析的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05

最新評論