Канонический способ сделать это - распределенная транзакция , использующая протокол двухфазной фиксации .
К сожалению, SQLite, похоже, не поддерживает его, но поскольку PostgreSQL делает, вы все равно можете использовать его, если задействованы только две базы данных:
BEGIN; -- on PostgreSQL
BEGIN; -- on SQLite
/*
* Do work on both databases.
* On error, ROLLBACK both transactions.
*/
PREPARE TRANSACTION 'somename'; -- PostgreSQL
COMMIT; -- SQLite
COMMIT PREPARED 'somename'; -- PostgreSQL
Теперь, если во время SQLite возникает ошибка COMMIT
, вы запускаете ROLLBACK PREPARED 'sonename'
на PostgreSQL. Идея состоит в том, что все, что может произойти сбой во время фиксации, выполняется во время PREPARE TRANSACTION
, и состояние транзакции сохраняется, так что она остается открытой, но все равно переживает перезапуск сервера.
Это безопасно, но есть предостережение. Подготовленные транзакции опасны, потому что они удерживают блокировки и удерживают VACUUM
от очистки (как и все другие транзакции), но они являются постоянными и сохраняются до тех пор, пока вы их явно не удалите. Таким образом, вам нужно некоторое программное обеспечение, диспетчер распределенных транзакций , которое является безопасным sh и отслеживает все распределенные транзакции. Этот менеджер транзакций может очистить все подготовленные транзакции после некоторого сбоя.