Как найти оскорбительную вставку из исключения BatchUpdateException?

Когда у меня возникает 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, если это уместно.

Заранее благодарю за любой совет.

--Джеймс


person James Adams    schedule 07.09.2010    source источник


Ответы (1)


Из документации API Java для BatchUpdateException:

После того как команда в пакетном обновлении не выполняется должным образом и возникает исключение BatchUpdateException, драйвер может продолжить или не продолжить обработку оставшихся команд в пакете. Если драйвер продолжает обработку после сбоя, массив, возвращаемый методом BatchUpdateException.getUpdateCounts, будет содержать элемент для каждой команды в пакете, а не только элементы для команд, успешно выполненных до возникновения ошибки. В случае, когда драйвер продолжает обработку команд, элементом массива для любой невыполненной команды является Statement.EXECUTE_FAILED.

Теперь я не уверен в поведении драйвера Oracle JDBC, который вы используете, но очевидно, что любой из упомянутых методов должен работать - если в массиве, возвращаемом вызовом BatchUpdateException.getUpdateCounts, есть N элементов, то Обработано N элементов в пакете. Или, если возвращаемый массив имеет тот же размер, что и количество операторов в пакете, то все элементы массива, значение которых равно Statement.EXECUTE_FAILED, не будут выполняться в пакете.

person Vineet Reynolds    schedule 07.09.2010
comment
Спасибо, Винит, за то, что обратила мое внимание на эту очень полезную информацию. Очень ценю! - person James Adams; 08.09.2010