commit() должен быть вызван перед извлечением значений для параметров out?
При написании java JDBC-кода для вызова хранимой процедуры я использую con.setAutoCommit(false);
У меня вопрос в чем разница в следующих подходах:
Подход-1:
con = DBConnection.getConnection();
con.setAutoCommit(false);
stmt= con.prepareCall("{call updateEmp(?,?,?,?,?,?)}");
stmt.setInt(1, id);
stmt.setString(2, name);
stmt.setString(3, role);
stmt.registerOutParameter(6, java.sql.Types.VARCHAR);
stmt.executeUpdate();
con.commit();
//read the OUT parameter AFTER commit
String result = stmt.getString(6);
или Подход-2:
// Read the OUT parameter BEFORE commit
String result = stmt.getString(6);
con.commit();
5 ответов
Мне кажется, что в случаях, когда параметр out является простым типом, это в большей степени вопрос стиля. Однако выходной параметр может быть, например, курсором. В случае автоматической фиксации операция фиксации происходит только тогда, когда все наборы результатов, которые возвращаются выходными параметрами типа курсора или хранимой процедурой, закрыты. Если коммит выдан до полного извлечения курсора, согласованность данных сомнительна. Чтобы избежать такой неоднозначности, я бы предложил зафиксировать / откатить транзакцию после того, как все параметры прочитаны.
Я думаю, это будет зависеть от того, выполняет ли хранимая процедура, которую вы вызываете, свой коммит или нет. Я ожидал бы процедуру обновления, которая принимает параметры и устанавливает параметры для внутренней фиксации или отката.
В этом случае вызов setAutoCommit(true) или вызов con.commit() не будут иметь никакого эффекта, а параметр out будет иметь значение независимо от того, когда вы вызываете stmt.getString(6). Если в самой хранимой процедуре нет коммита, я ожидаю, что ваш параметр out будет нулевым, если вы вызовете con.commit() после вызова stmt.getString(6).
Разница в обработке исключений. Если getString выдает исключение, то следующий коммит не будет выполнен. Последствия зависят от того, есть ли какие-либо изменения в текущей транзакции **. Если бы вы следили за двумя версиями кода (где исключение не генерировалось), а затем сравнивали два файла трассировки, вы не смогли бы определить, какая версия кода создала каждую трассу, если вы не оставили маркеры какого-либо вида (или сохранил спиды для каждого пользовательского процесса).
Вы должны задать себе вопрос: хочу ли я совершить, даже если будут выброшены исключения? Тогда вы будете знать, как написать код.
** Ваше соединение всегда имеет открытую транзакцию. Некоторые транзакции имеют изменения, а другие нет.
Основное отличие состоит в том, что вы держите транзакцию открытой дольше, чем необходимо. Вы всегда должны пытаться совершить как можно быстрее, чтобы минимизировать возможность блокировки других транзакций. Особенно, если вы делаете что-то вроде передачи большого двоичного объекта или большого текстового поля, которое потенциально может связать много места в журнале транзакций (а также занять больше времени для передачи по проводам).
Просто суммируя приведенные выше ответы в одном ответе, вы получите краткое резюме:
1- При фиксации, прежде чем все параметры будут прочитаны, согласованность данных сомнительна. Так что здесь подход-2 не рекомендуется.
2. Предположим, что при чтении выходных параметров возникает исключение, тогда транзакция не будет зафиксирована. С другой стороны, если мы хотим, чтобы транзакция была зафиксирована, не заботясь о выходных параметрах, мы можем зафиксировать ее перед чтением.
3 - При подходе 2 мы блокируем транзакцию на более длительное время. В приведенном выше примере кода это не имеет большого значения, но это может быть проблемой, когда мы делаем много вещей перед фиксацией.