如何从 BatchUpdateException 中找到有问题的插入?

发布于 2024-09-18 10:41:26 字数 2327 浏览 8 评论 0原文

当我因唯一约束违规而出现 BatchUpdateException 时,是否有办法确定批量插入中的哪条记录违规?例如,假设我通过调用PreparedStatement.executeBatch() 执行批量插入,并且捕获了BatchUpdateException,其原因是“ORA-00001:违反了唯一约束(ABC.SYS_123)”。使用 Eclipse 进行调试时,这大约是我可以从该异常中获得的尽可能多的信息,但我想找出哪个实际插入导致违反唯一约束。有什么办法可以找到这些信息吗?

我的代码目前看起来(或多或少)像这样:

public void batchInsert(final Collection<MyObject> objectCollection)
{
    try
    {
        if (connection == null)
        {
            connection = getJdbcTemplate().getDataSource().getConnection();
        }

        // get the last entity ID value so we can know where to begin
        Long entityId = getJdbcTemplate().queryForLong("SELECT MAX(" + MyObject.ID_COLUMN_NAME +
                                                       ") FROM " + MyObject.TABLE_NAME);
        entityId++;

        // get a date to use for the created and updated dates
        Date now = new Date(new java.util.Date().getTime());

        // set auto commit to false so we can batch save without committing each individual insert
        connection.setAutoCommit(false);

        // create the prepared statement
        String insertSql = "INSERT INTO " + MyObject.TABLE_NAME + " (" +
                           MyObject.ID_COLUMN_NAME + ", VALUE_1, VALUE_2) " +
                           "VALUES (?, ?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(insertSql);

        // add a batch entry for each of the SurfaceMetObservations objects
        for (MyObject object : objectCollection)
        {
            preparedStatement.setLong(1, entityId);
            preparedStatement.setBigDecimal(2, object.getValue1());
            preparedStatement.setBigDecimal(3, object.getValue2());
            preparedStatement.addBatch();
            entityId++;
        }

        int updateCounts[] = preparedStatement.executeBatch();
        preparedStatement.close();
        if (confirmUpdateCounts(updateCounts))
        {
            connection.commit();
        }
        else
        {
            connection.rollback();
            throw new RuntimeException("One or more inserts failed to execute.");
        }
    }
    catch (SQLException ex)
    {
        throw new RuntimeException(ex);
    }
}

我正在使用 Spring 的 JdbcTemplate 和 Oracle 11G 数据库(如果相关的话)。

预先感谢您的任何建议。

——詹姆斯

When I have a BatchUpdateException as the result of a unique constraint violation is there a way for me to determine which record in the batch insert is in violation? For example let's say I'm performing a batch insert by calling PreparedStatement.executeBatch() and I catch the BatchUpdateException which has as it's cause "ORA-00001: unique constraint (ABC.SYS_123) violated". When debugging using Eclipse this is about as much info as I can coax from this exception, but I'd like to find out which actual insert is causing the violation of the unique constraint. Is there a way I can find this information?

My code currently looks (more or less) like this:

public void batchInsert(final Collection<MyObject> objectCollection)
{
    try
    {
        if (connection == null)
        {
            connection = getJdbcTemplate().getDataSource().getConnection();
        }

        // get the last entity ID value so we can know where to begin
        Long entityId = getJdbcTemplate().queryForLong("SELECT MAX(" + MyObject.ID_COLUMN_NAME +
                                                       ") FROM " + MyObject.TABLE_NAME);
        entityId++;

        // get a date to use for the created and updated dates
        Date now = new Date(new java.util.Date().getTime());

        // set auto commit to false so we can batch save without committing each individual insert
        connection.setAutoCommit(false);

        // create the prepared statement
        String insertSql = "INSERT INTO " + MyObject.TABLE_NAME + " (" +
                           MyObject.ID_COLUMN_NAME + ", VALUE_1, VALUE_2) " +
                           "VALUES (?, ?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(insertSql);

        // add a batch entry for each of the SurfaceMetObservations objects
        for (MyObject object : objectCollection)
        {
            preparedStatement.setLong(1, entityId);
            preparedStatement.setBigDecimal(2, object.getValue1());
            preparedStatement.setBigDecimal(3, object.getValue2());
            preparedStatement.addBatch();
            entityId++;
        }

        int updateCounts[] = preparedStatement.executeBatch();
        preparedStatement.close();
        if (confirmUpdateCounts(updateCounts))
        {
            connection.commit();
        }
        else
        {
            connection.rollback();
            throw new RuntimeException("One or more inserts failed to execute.");
        }
    }
    catch (SQLException ex)
    {
        throw new RuntimeException(ex);
    }
}

I am using Spring's JdbcTemplate and an Oracle 11G database, in case that is relevant.

Thanks in advance for any advice.

--James

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凡尘雨 2024-09-25 10:41:26

来自 BatchUpdateException 的 Java API 文档:

执行批量更新命令后
无法正确执行并且
抛出 BatchUpdateException ,
司机可能会也可能不会继续
处理剩余的命令
批。如果司机继续
失败后的处理,数组
方法返回的
BatchUpdateException.getUpdateCounts
每个命令都有一个元素
在批处理中而不是仅在元素中
对于执行的命令
错误发生前成功。在
驾驶员继续行驶的情况
处理命令,数组元素
对于任何失败的命令是
语句.EXECUTE_FAILED。

现在,我不确定您正在使用的 Oracle JDBC 驱动程序的行为,但显然上述任何一种技术都应该有效 - 如果调用 BatchUpdateException.getUpdateCounts 返回的数组中有 N 个元素,则批次中的 N 个元素已被处理。或者,如果返回的数组的大小与批处理语句的数量相同,则值为 Statement.EXECUTE_FAILED 的所有数组元素都将在批处理中执行失败。

From the Java API documentation of BatchUpdateException:

After a command in a batch update
fails to execute properly and a
BatchUpdateException is thrown, the
driver may or may not continue to
process the remaining commands in the
batch. If the driver continues
processing after a failure, the array
returned by the method
BatchUpdateException.getUpdateCounts
will have an element for every command
in the batch rather than only elements
for the commands that executed
successfully before the error. In the
case where the driver continues
processing commands, the array element
for any command that failed is
Statement.EXECUTE_FAILED.

Now, I'm unsure about the behavior of the Oracle JDBC driver that you are using, but it is apparent that either of the techniques mentioned should work - if there are N elements in the array returned by the call to BatchUpdateException.getUpdateCounts, then N elements in the batch have been processed. Or, if the array returned has the same size as the number of batched statements, then all the array elements whose value is Statement.EXECUTE_FAILED would have failed execution in the batch.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文