tddl 支持批量插入的方法

tddl相關

https://www.programcreek.com/java-api-examples/?code=loye168/tddl5/tddl5-master/tddl-group
https://github.com/ninqing/hermes/wiki/Tddl_Rulejava

前言

本例是用apply_no爲分表分庫鍵node

mybatis中:git

  1. #{  }是預編譯處理,MyBatis在處理#{  }時,它會將sql中的#{  }替換爲?,而後調用PreparedStatement的set方法來賦值;
  2. ${  }是字符串替換, MyBatis在處理${  }時,它會將sql中的${  }替換爲變量的值。

mapper.xml文件中的方法先被mybatis先處理: # 轉爲佔位符 , $ 則是直接注入值, 再被TDDL來處理。
通過驗證: 
必定要是APPLY_NO=${applyNo}」這樣的寫法!github

int insertBatch(@Param("applyNo") String applyNo, @Param("list")List<DecisionExecNode> list);
 <insert id="insertBatch" parameterType="java.util.List" >
     /*+TDDL({type:'condition',params:[{"paramtype":"long","expr":["APPLY_NO=${applyNo}"]}],vtab:'decision_exec_node'})*/

    insert into decision_exec_node (
      id, 
      apply_no, 
      case_no, 
      product_code 
      )
    values 
    <foreach collection="list" item="item"  separator=",">
     (  #{item.id,jdbcType=BIGINT}, 
        #{item.applyNo,jdbcType=VARCHAR}, 
        #{item.caseNo,jdbcType=VARCHAR}, 
        #{item.productCode,jdbcType=VARCHAR} )
     </foreach>
  </insert>
  •  expr: 參數表達式,本例寫的是TDDL分表鍵 
  •  vtab: 表名
  • /*+tddl_group({groupIndex:0,failRetry:true})*/ 能夠強制指定數據庫。   groupIndex: 標識同一個group下的多個dataSource(讀&寫庫等)

在tddl-client  3.3.2.4 中的 SimpleHintParser 最末端有個測試用例, 對於使用格式在此類中處理! sql

  • SimpleHintParser:  在TPreparedStatementImp路由獲取真實的TGroupDataSource以前執行  (選擇Group)
  • GroupHintParser: 在TGroupPreparedStatement獲取真實Connection以前執行 (選擇Group下強制指定庫druid)

在網上找到一些關於SimpleHintParser的使用事例: https://www.programcreek.com/java-api-examples/?api=com.taobao.tddl.optimizer.parse.hint.SimpleHintParser。沒試過每個用例,權當解決問題的一種思路。數據庫

驗證過程

具體能夠關注SimpleHintParser.convertHint2RouteCondition方法中的入參StartInfo對象的屬性sql和sqlParam 在不一樣hint寫法下構建tddlHint是有區別的。會取第一個param來注入api

分表規則: 

如下的方法是:  SimpleHintParser.decodeComparativemybatis

錯誤1: "expr":["APPLY_NO=#applyNo#"] 

這種會直接按字符串「#applyNo#」進行路由分表,致使數據分表不一致!!
app

錯誤2: "expr":["APPLY_NO=?"]

這種會直接按取第一個佔位符指定的參數值來填充。 但比較奇怪的是拿不到傳入的「applyNo」, 只會拿到「List」對象裏的第一個param 填充(applyNo像被丟了同樣,推測是由於在mapper文件方法體內並無對其進行直接使用,mybatis解析時會過濾多餘的屬性值), 致使最後因填充參數不足插入失敗測試

錯誤3:"expr":["APPLY_NO=#{applyNo,jdbcType=VARCHAR}"]  

這種原本應該是最接近真相的方式,這種方式能夠讀取到額外傳入的「applyNo」 的屬性值, 但比較奇怪的是在SimpleHintParser處理時調用的HintParserHelper.extractHint方法會斷定這個參數是不是「setString」, 會給真實值先後加入了單引號! 這個致使VirtualTableRuleMatcher.findMatchedRule的入參map值與正常處理情景下的不一致! 最終致使會在WrappedGroovyRule執行eval方法路由的時候異常!


最終獲得的對象是:

但正常狀況下應該是:

異常時的入參倒是:

那能不能直接傳遞hashCode進去呢? 最後驗證發現然並軟。。分表規則是先轉成String再hash, 仍是不行。。

正確方法:APPLY_NO=${applyNo}

根據推測: mybatis對於「#」會轉爲佔位符,那直接在拼接sql的時候拼入分庫分表鍵值,跳過SimpleHintParser中對String類型參數的額外補單引號動做!

這下正常了:
GroovyRule

相關源碼

SimpleHintParser

TPreparedStatementImp執行executeQuery(其餘方法相似)時,經過buildSqlExecutionContextUsePipeline來獲取真實的group信息。

GroupHintParser

咱們來看TGroupPreparedStatement執行的executeQuery(其餘方法相似):會經過TConnection獲取真實的TGroupConnection。

此時將經過GroupHintParser來處理sql獲取指定的GroupIndex

這個GroupIndex用在AbstractDBSelector的tryExecute方法中選擇當前Group下匹配的DataSourceHolder


RuleLePipelineFactory

處理鏈路handler

相關文章
相關標籤/搜索