使用 addBatch 和 executeBatch 时是不是必须使用相同的 prepareCall?为啥?
Posted
技术标签:
【中文标题】使用 addBatch 和 executeBatch 时是不是必须使用相同的 prepareCall?为啥?【英文标题】:Do I have to use the same prepareCall when using addBatch & executeBatch? Why?使用 addBatch 和 executeBatch 时是否必须使用相同的 prepareCall?为什么? 【发布时间】:2021-10-10 16:20:57 【问题描述】:我是使用 JDBC 的新手,正在学习如何使用批处理。在浪费了很多时间试图弄清楚为什么我的 javascript 和 SQL 存储过程的组合不起作用之后,我想我知道在使用 addBatch
和 executeBatch
时必须使用一个 prepareCall
。这是真的?如果有,为什么?
举例来说,这里有一些示例输入:
var vals = [["value1_1","value2_1","value3","value4","value5","value6_1"],
["value1_2","value2_2","value3","value4","value5","value6_2"]]
下面的循环按预期工作。注意我在进入循环之前prepareCall
。
params = Array(vals.length).fill("?")
pstmt = conn.prepareCall("call "+storedProcedure+"("+params+")");
for (var i = 0; i < vals.length; i++) // for each array
for (var j = 0; j < vals[i].length; j++) // for each value within each array
// set the string
pstmt.setString(j+1, vals[i][j]);
pstmt.addBatch();
try
pstmt.executeBatch();
catch (err)
//my err msg code
pstmt.close();
conn.close();
现在,有时我的记录具有不同数量的参数,所以我想我可以将 prepareCall
移动到第一个循环中,这样我就可以根据需要更改每个输入数组的参数数量。
for (var i = 0; i < vals.length; i++) // for each array
// moved prepareCall here
params = Array(vals.length).fill("?")
pstmt = conn.prepareCall("call "+storedProcedure+"("+params+")");
for (var j = 0; j < vals[i].length; j++) // for each value within each array
// set the string
pstmt.setString(j+1, vals[i][j]);
pstmt.addBatch();
try
pstmt.executeBatch();
catch (err)
//my err msg code
pstmt.close();
conn.close();
对于第二个循环,我没有从 Javascript 中得到任何错误,但我从我的存储过程中得到了一个外部约束错误。我的存储过程创建了一组CALL
s 来根据最后一个参数的值创建记录。我知道我得到的错误是告诉我FK
s 之一不存在。仅当调用了错误的 CALL
s 集或调用了正确的 CALL
s 集但其中一个 CALL
s 失败时,才会发生这种情况。我确定这两个都不是问题,因为第一个循环按预期工作。
因此,我有兴趣了解为什么我在executeBatch
时必须使用一个prepareCall
?为了确认,当我使用不同数量的参数调用不同的存储过程时,我必须使用完全独立的prepareCall
s?
我认为这无关紧要,但为了更好的衡量标准:我使用的是 mysql 5.7。
【问题讨论】:
【参考方案1】:方法prepareCall
返回一个CallableStatement
对象,该对象是为您传递给prepareCall
的特定语句编译的。当您调用addBatch
时,参数集将添加到CallableStatement
的特定实例中。如果您再次执行prepareCall
,您将获得一个不同的 CallableStatement
句柄,并带有自己的批处理。
因此,在外循环每次迭代的第二段代码中,您创建了一个 new CallableStatement
,丢失了先前的可调用语句及其批处理(在您的代码,可能在您的 DBMS 中)。结果,当你调用executeBatch
时,你只会执行你准备好的last语句,只有一组参数值。
如果需要执行不同的语句文本,需要按顺序准备执行,不能使用batch(*)。
* - 如果多组参数使用相同的语句文本,您可以使用批处理,但如果不同语句文本之间存在顺序依赖关系,这可能会变得很棘手
【讨论】:
以上是关于使用 addBatch 和 executeBatch 时是不是必须使用相同的 prepareCall?为啥?的主要内容,如果未能解决你的问题,请参考以下文章
JDBC批量插入数据优化,使用addBatch和executeBatch
JDBC批量插入数据优化,使用addBatch和executeBatch
java中的PreparedStatement.addBatch有啥限制吗?