JDBC PreparedStatement、批量更新和生成的Keys

Posted

技术标签:

【中文标题】JDBC PreparedStatement、批量更新和生成的Keys【英文标题】:JDBC PreparedStatement, Batch Update and generated Keys 【发布时间】:2012-02-22 08:47:47 【问题描述】:

我在批量使用 jdbcpreparedStatement 并尝试获取由此创建的生成密钥时遇到问题。

代码:

        PreparedStatement stmt = null;
    ...
    connection.setAutoCommit(false);
    stmt = connection.prepareStatement(insertSuspiciousElement,new String[] "external_id","element_id");
final int elementBatchSize = 5000;
    int elementCount =0;
        for(BlSuspiciousElement element : elements)
        externalIds.add(element.getExternalId());
        stmt.setInt(1, element.getBlElementType().getElementTypeId());
        stmt.setString(2, element.getFirstname());
        stmt.addBatch();
        elementCount++;
        if(elementCount % elementBatchSize == 0)
            System.out.println("Running query with batch size for suspiciousElement");
            stmt.executeBatch();

            ResultSet keys = stmt.getGeneratedKeys();
            while(keys.next())
                externalIdElementIdMapping.put(keys.getInt("external_id"),keys.getInt("element_id"));
            
            keys.close();
            stmt.clearBatch();
            stmt.clearParameters();
            stmt.clearWarnings();
            System.out.println("Done query with batch size for suspiciousElement");
        
        

在第一个 stmt.executeBatch() 方法处失败。

错误:

[30/01/12 15:54:41:684 CET] 00000029 RemoteExcepti E   CNTR0020E: EJB threw an unexpected (non-declared) exception during invocation of method "processFullFeedForPepAndRelationUpdateOnly" on bean "BeanId(CoRelateEar#AmlKycToolBO.jar#FactivaDBUpdater, null)". Exception data: java.lang.ArrayIndexOutOfBoundsException
at oracle.jdbc.driver.T4CNumberAccessor.unmarshalOneRow(T4CNumberAccessor.java:201)
at oracle.jdbc.driver.T4C8Oall.readRXD(T4C8Oall.java:696)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:340)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1044)
at oracle.jdbc.driver.OraclePreparedStatement.executeForRowsWithTimeout(OraclePreparedStatement.java:10143)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10249)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:230)
at com.ibm.ws.rsadapter.jdbc.WSJdbcStatement.executeBatch(WSJdbcStatement.java:748)

对我来说不是很明显......

好像不能批量更新?仅用于语句或准备好的语句。在这种情况下,我想我最好尝试进行批量插入,然后运行另一个查询来查找每个已创建元素的生成键...

感谢您的帮助,

F

【问题讨论】:

【参考方案1】:

我认为您应该告诉 Oracle JDBC 驱动程序您将检索生成的密钥。

查看以下问题的已接受答案以了解详细信息:PreparedStatement with Statement.RETURN_GENERATED_KEYS。

编辑 1/31/12:如果这种方法不适用于批处理(而且我没有尝试使用批处理),您可以代替批处理,只需关闭自动提交,插入所有数据,然后然后提交。在我的实验中,这种方法的性能损失仅为 3%。我还在 SO 上找到了另一个类似的建议:mysql batch stmt with Statement.RETURN_GENERATED_KEYS。

【讨论】:

这个链接只使用preparedStatement。我的问题是当我尝试在批量执行的preparedStatement 中检索生成的密钥时......略有不同。 @Farid:您在准备语句时是否尝试指定 RETURN_GENERATED_KEYS?类似于:stmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); @Farid:你会考虑一个接一个地插入记录,然后明确地进行 1 次提交而不是批处理吗? 我正在考虑。当我插入大约 100 万条记录时,我怀疑不使用批处理模式会导致性能问题...... 前段时间,我正在对 Oracle 中加载数据的不同方式进行基准测试。我正在加载 3 个字段的记录,总长度为 100 字节。性能似乎更依赖于提交大小,每次提交的峰值在 2500 到 10K 条记录之间。我正在使用批处理,但提交中的 30 和 1000 批次之间没有明显的区别。提交中的单批 10K 记录的表现明显更差。另一个考虑因素:当插入 1M 条记录并使用从序列生成的键时,在该序列上将 CACHE 设置为 1000 非常有用。

以上是关于JDBC PreparedStatement、批量更新和生成的Keys的主要内容,如果未能解决你的问题,请参考以下文章

JDBC批量插入性能简单分析

jdbc批量插入实现大批量数据快速插入

PreparedStatement批量(batch)插入数据

JDBC中Statement与PreparedStatement的区别

MYSQL 之 JDBC: PreparedStatement

JDBC的批量添加