前因:最近要求开发一个日终调度任务,计算数据并落地到某个数据表中,对于资深的一个crud人员,这是一个炒鸡简单的事情:当然时批量计算插入咯。那么问题就出来了,我打算每500次做一次插入,结果一直报错,ORA-01722: 无效数字,wtf。
插入语句动态拼接:
StringBuilder builder = new StringBuilder();
builder.append("BEGIN <foreach collection=\"list\" item=\"item\" separator=\";\">");
builder.append(insert).append(columns).append(" VALUES ").append(values).append("</foreach>").append(" ;END;");
return builder.toString();
落地代码:
index++;
if (index == 500) {
calLandMapper.batchInsert(calLands);
index = 0;
calLands.clear();
log.info("数据落地成功");
}
问题排查:
第一步:问题是无效数字,那首先怀疑是插入的数据中存在非数字类型,null等,于是断点跟踪,发现并没有任何一条数据有问题,于是,把批量插入改成单个插入,欸,没有问题。wc,什么鬼
第二步:发现了一个神奇的小插件,MyBatis Log Plugin插件: 把日志中运行的sql自动进行拼装,然后单独分离出来打印到sql的控制台。安装步骤如下(idea):
Settings–>Plugins–>在Marketplace中搜索MyBatis Log Plugin,install(当然这个是收费的,可以付钱购买)
当然我这里提供一个破解版,可私聊我要,直接在Settings–>Plugins–>Install Plugin From Disk,选择下载的jar包导入,重启即可,安装成功如下:
点击MyBatis Log Plugin会有控制台界面展示,
通过以上打印出来的sql语句在plsql中执行,…额,语句太长卡死了,于是便每100条执行,没有问题(问号脸???)
第三步:于是,前后想了许久,喝了杯茶,灵光一闪,会不会是语句太长被截断了,于是index=200,每200句执行一次,批量插入ok。证明了我的灵光。
但是问题又来了,是字符串太长被截断还是sql语句被MyBatis截断了呢。验证,
String长度限制:(百度:https://blog.csdn.net/debugbugbg/article/details/90022728)
// a...a代表65534个a
String s = "a...a";
System.out.println(s);
// a...a代表65535个a,报字符串过长
String s1 = "a...a";
System.out.println(s1);
StringBuffer,StringBuilder长度限制:
// a...a代表65534个a
String str = "a...a";
while(true){
stringBuffer.append(str);
System.out.println(stringBuffer.length());
}
在字符串长度为351720978长度的时候,内存溢出(是不是可以再复习一下堆内存分配和jvm调优)
烤,我这个大傻X,字符串长度限制也不会被截断呀,顶多过长或是内存溢出报错呀。最终可以确定,是Mybatis对sql语句长度有限制,但是限制是多少呢?待我研究研究再记录下来。。。
有所思:每一个错误都将督促我进步,每一个问题都应该被扩散分析