Isso não é culpa do PDO, é inerente ao gerenciamento de transações do PostgreSQL. Ver:
a>
O PostgreSQL não reverte a transação, mas a configura para um estado abortado onde só pode reverter e onde todas as instruções, exceto
ROLLBACK
reportar um erro:(Estou surpreso por não encontrar isso mencionado na documentação oficial; acho que precisarei escrever um patch para melhorar isso.)
Então. Quando você tenta/captura e engole a exceção no PDO, você está capturando uma exceção do lado do PHP, mas não está alterando o fato de que a transação do PostgreSQL está em um estado abortado.
Se você quiser engolir exceções e continuar usando a transação, você deve criar um
SAVEPOINT
antes de cada instrução que pode falhar. Se falhar, você deve ROLLBACK TO SAVEPOINT ...;
. Se for bem-sucedido, você pode RELEASE SAVEPOINT ...;
. Isso impõe sobrecarga extra no banco de dados para gerenciamento de transações, adiciona viagens de ida e volta e queima IDs de transação mais rapidamente (o que significa que o PostgreSQL precisa fazer mais trabalho de limpeza em segundo plano). Geralmente, é preferível projetar seu SQL para que ele não falhe em circunstâncias normais. Por exemplo, você pode validar a maioria das restrições do lado do cliente, tratando as restrições do lado do servidor como um segundo nível de garantia enquanto captura a maioria dos erros do lado do cliente.
Onde isso for impraticável, torne seu aplicativo tolerante a falhas, para que ele possa tentar novamente uma transação com falha. Às vezes, isso é necessário de qualquer maneira - por exemplo, você geralmente não pode usar pontos de salvamento para recuperar de deadlocks, abortos de transações ou falhas de serialização. Também pode ser útil manter as transações propensas a falhas o mais curtas possível, fazendo apenas o trabalho mínimo necessário, para que você tenha menos para acompanhar e repetir.
Portanto:Sempre que possível, em vez de engolir uma exceção, execute o código de banco de dados propenso a falhas em um loop de repetição. Certifique-se de que seu código mantenha um registro das informações necessárias para tentar novamente toda a transação em caso de erro, não apenas a declaração mais recente.
Lembre-se, qualquer a transação pode falhar:O DBA pode reiniciar o banco de dados para aplicar um patch, o sistema pode ficar sem RAM devido a um cron job descontrolado, etc. Portanto, aplicativos tolerantes a falhas são um bom design de qualquer maneira.
Parabéns por pelo menos usar exceções de PDO e lidar com exceções - você já está muito à frente da maioria dos desenvolvedores.