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

相关文章
相关标签/搜索