Пакетное обновление JDBC пропускается при начальном наборе операторов обновления
Мы используем пакетное обновление JDBC (Statement - void addBatch( String sql) и int[] executeBatch()) в нашем коде Java. Задание должно вставлять около 27 тыс. Записей в таблицу, а затем обновлять около 18 тыс. Записей в следующем пакете.
Когда наша работа выполняется в 6 утра, она пропускает несколько тысяч записей (мы наблюдали это из журналов аудита базы данных). Из журналов заданий видно, что операторы обновления генерируются для всех записей 18 тыс. Мы понимаем, что все операторы обновления добавляются в пакет последовательно, однако, кажется, что отсутствуют только записи с начала пакета. Кроме того, это не фиксированное число каждый день - в один день оно пропускает первые 4534 оператора обновления, а в другой день пропускает первые 8853 записи, а в другой день пропускает 5648 записей.
Сначала мы думали, что это может быть проблема с потоком, но с тех пор отошли от этого мыслительного процесса, поскольку пропускаемый блок не всегда содержит одинаковое количество операторов обновления. Если предположить, что первые несколько тысяч обновлений происходят еще до вставки, то эти обновления должны как минимум отображаться в журналах аудита базы данных. Однако, это не так.
Мы думаем, что это связано с проблемой памяти / кучи, поскольку выполнение задания в любое другое время забирает все 18k операторов обновления, и они выполняются успешно. Мы просмотрели журналы аудита из базы данных Oracle и заметили, что отсутствующие операторы обновления никогда не выполняются в таблице во время пробежки в 6 утра. В любое другое время все операторы обновления отображаются в журналах аудита базы данных.
Эта работа успешно выполнялась в течение почти 3 лет, и такое поведение началось только несколько недель назад. Мы пытались взглянуть на любые изменения в сервере / среде, но у нас ничего не выскакивает.
Мы пытаемся точно определить, почему это происходит, в частности, если есть какие-либо процессы, которые используют слишком много кучи JVM, и в результате наши операторы обновления перезаписываются / не выполняются.
База данных: Oracle 11g Enterprise Edition, выпуск 11.2.0.3.0 - 64-битная Java: Java-версия "1.6.0_51" Java(TM) SE Runtime Environment (сборка 1.6.0_51-b11) Java HotSpot(TM) Виртуальная машина сервера (сборка 20.51-b01) смешанный режим)
void main()
{
DataBuffer dataBuffer;//assume that all the selected data to be updated is stored in this object
List<String> TransformedList = transform(dataBuffer);
int status = bulkDML(TransformedList);
}
public List<String> transform(DataBuffer i_SourceData)
{
//i_SourceData has all the data selected from
//the source table, that has to be updated
List<Row> AllRows = i_SourceData.getAllRows();
List<String> AllColumns = i_SourceData.getColumnNames();
List<String> transformedList = new ArrayList<String>();
for(Row row: AllRows)
{
int index = AllColumns.indexOf("unq_idntfr_col");
String unq_idntfr_val = (String)row.getFieldValues().get(index);
index = AllColumns.indexOf("col1");
String val1 = (String)row.getFieldValues().get(index);
String query = null;
query = "UPDATE TABLE SET col1 = " + val1 + " where unq_idntfr_col=" + unq_idntfr_val;//this query is not the issue either - it is parameterized in our code
transformedList.add(query);
}
return transformedList;
}
public int bulkDML(List<String> i_QueryList)
{
Connection connection = getConnection();
Statement statement = getStatement(connection);
try
{
connection.setAutoCommit(false);
for (String Query: i_QueryList)
{
statement.addBatch(Query);
}
statement.executeBatch();
connection.commit();
}
//handle various exceptions and all of them return -1
//not pertinent to the issue at hand
catch(Exception e)
{
return -1;
}
CloseResources(connection, statement, null);
return 0;
}
Любые предложения будут с благодарностью, спасибо.
1 ответ
Если вы хотите выполнить несколько обновлений для одной и той же таблицы, тогда я предлагаю изменить ваш запрос, чтобы использовать привязки и PreparedStatement, потому что это действительно единственный способ сделать реальные пакетные операции DML с базой данных Oracle. Например, ваш запрос станет:
UPDATE TABLE SET col1=? WHERE unq_idntfr_col=?
и затем используйте пакетную обработку JDBC с тем же PreparedStatement. Это изменение потребует от вас пересмотра метода bulkDML, чтобы он принимал значения связывания в качестве параметра вместо SQL.
Тогда псевдокод JDBC будет выглядеть так:
PreparedStatement pstmt = connection.prepareCall("UPDATE TABLE SET col1=? WHERE unq_idntfr_col=?");
pstmt.setXXX(1, x);
pstmt.setYYY(2, y);
pstmt.addBatch();
pstmt.setXXX(1, x);
pstmt.setYYY(2, y);
pstmt.addBatch();
pstmt.setXXX(1, x);
pstmt.setYYY(2, y);
pstmt.addBatch();
pstmt.executeBatch();