Estou protegendo transações críticas com mutexes de aplicativos e arquivos SERIALIZABLE
.
Presumo que isso torne essas operações o mais ácidas possível, mas agora estou preocupado que as leituras possam causar falhas nessas transações de gravação devido ao bloqueio.
As leituras estão em transações de instrução preparadas libpqxx. Eu li os documentos , wiki e white paper , mas não consigo descobrir como configurar uma transação de leitura para que ela nunca arrisque uma falha de outra transação crítica de gravação serializável.
Não consigo determinar se os bloqueios causarão falhas de serialização. Eles podem?
As leituras não precisam ser perfeitamente ácidas porque o aplicativo compensa condições de corrida, dados antigos, etc. A principal preocupação é que as transações de gravação críticas serializáveis não falhem devido a outras leituras.
Como uma instrução preparada somente para leitura deve ser configurada de forma absolutamente para não arriscar outra falha de gravação de transação serializável?
Uma
READ ONLY
transação não pode fazer com que uma transação de gravação (que não execute DDL) falhe, a menos que ela use explicitamenteLOCK TABLE
ou bloqueios consultivos.READ ONLY
as transações não podemSELECT ... FOR SHARE
ouSELECT ... FOR UPDATE
. Como eles não podem fazer DML, o bloqueio mais forte que eles podem obter em uma tabela éACCESS SHARE
, que entra em conflito apenas com oACCESS EXCLUSIVE
bloqueio obtido por DDL.Nem uma transação somente leitura pode causar falhas de serialização se a transação de gravação for
SERIALIZABLE
, porque as falhas de serialização exigem que ambas as transações executem gravações. É sempre possível serializar logicamente uma transação somente leitura antes ou depois de uma transação de leitura/gravação, pois é impossível que elas sejam mutuamente interdependentes.Então: Deve ser bom usar
READ COMMITTED
ouSERIALIZABLE
transações, comREAD ONLY
, contanto que você não o faça explicitamenteLOCK TABLE
.Você também precisa certificar-se de não usar bloqueios consultivos que possam interagir entre os dois conjuntos de transações. Muito provavelmente você não usa bloqueios consultivos e pode esquecer isso completamente.
Separadamente, porém, um aplicativo deve estar preparado para lidar com falhas de serialização ou outras interrupções de transação. Qualquer projeto que tente evitar isso está quebrado. As transações podem ser abortadas devido a problemas no nível do sistema operacional/máquina host, ação do administrador, etc. Não confie em transações que "não podem falhar". Se você absolutamente deve fazer isso, você precisa usar two-phase commit , onde você
PREPARE TRANSACTION
(no ponto em que é garantido que o tx não pode deixar de confirmar), faz o outro trabalho que depende do tx confirmar com segurança, entãoCOMMIT PREPARED
. Se algo der errado com o outro trabalho, você podeROLLBACK PREPARED
. 2PC tem sobrecargas significativas e é melhor evitá-lo quando puder, mas às vezes simplesmente não há escolha.