Я знаю, что это очень старый тикет, но (по состоянию на 2017 год) PostgreSQL все еще имеет такое же поведение автоматического отката, когда что-то идет не так в коммите.Я хотел бы поделиться некоторыми мыслями здесь.
Я не знаю, сможем ли мы изменить это поведение, и мне это не нужно, возможно, для лучшего делегирования PostgreSQL, чтобы справиться с откатом для нас (он знает, что делает, верно?).Откат означает, что данные возвращаются в исходное состояние до неудачной транзакции, это означает, что измененные или вставленные данные из триггеров также будут отброшены.В логике ACID это то, что мы хотим.Допустим, вы сами управляете откатом на бэкэнде, если во время вашего пользовательского отката что-то пойдет не так или если во время отката вы изменили базу данных одновременно с внешними транзакциями, данные станут несогласованными и ваша структура, скорее всего,collapse.
Итак, зная, что PostgreSQL будет управлять своей собственной стратегией отката, возникает вопрос: «как я могу расширить стратегию отката?» .Первое, о чем вы должны подумать: «что вызвало сбой транзакции?» .В вашей структуре try / catch попытайтесь обработать все возможные исключения и снова запустите транзакцию или отправьте отзыв внешнему приложению с некоторыми соответствующими сообщениями "не делать".Для меня это лучший способ справиться с ситуацией, это меньше кода, меньше накладных расходов, больше контроля, удобнее для пользователя, и ваша база данных будет вам благодарна.
Последний момент, на котором я хочу пролить свет,Стандарт SQL имеет код sqlstate , который можно использовать для связи с внутренними модулями.Неудачная операция во время транзакции вернет код sqlstate, затем вы можете использовать эти коды для создания соответствующих недостатков.Вы можете создавать свои собственные коды sqlstate, если они не связаны с зарезервированными (https://www.postgresql.org/message-id/20185.1359219138%40sss.pgh.pa.us). Например, в функции plpgsql
...
$$
begin
...do something...if it goes wrong
raise exception 'custom exception message' using errcode='12345';
end
$$
...
Это пример использования PDO в PHP(используя код ошибки выше):
...
$pdo->beginTransaction();
try {
$s = $pdo->prepare('...');
$s->execute([$value]);
/**
* Simulate a null violation exception
* If it fails, PDO will not wait the commit
* and will throw the exception, the code below
* is not executed.
*/
$s->execute([null]);
/**
* If nothing wrong happened, we commit to change
* the database state.
*/
$pdo->commit();
}
catch (PDOException $e) {
/**
* It is important to also have the commit here.
* It will trigger PostgreSQL rollback.
* And make the pdo Object back to auto-commit mode.
*/
$pdo->commit();
if ($e->getCode() === '12345') {
send_feedback_to_client('please do not hack us.');
}
}
...