起因


第二次客户端传入的数据如下:

select * from tablename后显示结果如下(其中
a字段为主键):

a:"3"与
a:"4"相关的两条数据却没插入成功。


select * from tablename后显示结果如下:

排错过程


Hive41PreparedStatement,是ImpalaJDBC提供的,其中关键的两个字段是
m_prepareSql和
m_parameterInputValues:



ImpalaInsertQueryGenerator的主要作用是将
?参数替换为实际的参数值并生成最终执行的SQL语句。值得说明的是,upsert语句在JDBC底层是使用Insert的语法解析器,并通过执行器
m_upsertQuery开关将
insert替换为
upsert。
ImpalaInsertQueryGenerator通过
IPTNode接口的递归调用来实现AST解析。
ImpalaInsertQueryGenerator中有一段解析ListNode的代码,大意如下:

paramPTListNode中每一个元素提出来进行单独的适配,而单独适配的函数大意如下:

(?,?),(?,?),这是一个嵌套list类型,所以在
visitChildren匹配时会将进入
visit(PTListNode paramPTListNode)函数进行单项匹配。可是
this.m_contexts中存放了所有的input内容,所以
m_paramValues变量中其实存了n*n*m个元素,其中n为表达式list的长度,m为表达式list每一个sublist的长度。在最后生成sql时,
ImpalaInsertQueryGenerator会从
m_paramValues中逐个poll出解析的语句,长度为n*m。又因为
ImpalaInsertQueryGenerator是一个singleton,所以第二次客户端调用时,仍然会从
m_paramValues中poll出,即poll出了原来的元素,至此真相大白。有兴趣的小伙伴也可以根据这个逻辑看看第二个测试用例是怎么错的。
解决
m_paramValues的add数量(n*n*m)和poll数量(n*m)不一致造成的,m是恒定的,所以只能改n。当n=1时,n*n=n,所以将Mybatis中的多条语句批量upsert变成单条upsert即可以绕过问题,测试通过。
文章转载自等我放学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




