Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como detectar que a transação já foi iniciada?


A estrutura não tem como saber se você iniciou uma transação. Você pode até usar $db->query('START TRANSACTION') que a estrutura não saberia porque não analisa as instruções SQL que você executa.

O ponto é que é uma responsabilidade do aplicativo rastrear se você iniciou uma transação ou não. Não é algo que o framework possa fazer.

Eu sei que alguns frameworks tentam fazer isso e fazem coisas absurdas como contar quantas vezes você iniciou uma transação, só resolvendo quando você fez commit ou rollback um número correspondente de vezes. Mas isso é totalmente falso porque nenhuma de suas funções pode saber se commit ou rollback realmente fará isso, ou se eles estão em outra camada de aninhamento.

(Você pode dizer que eu tive essa discussão algumas vezes? :-)

Atualização 1: Propulsão é uma biblioteca de acesso ao banco de dados PHP que suporta o conceito de "transação interna" que não é confirmada quando você diz. O início de uma transação apenas incrementa um contador e a confirmação/reversão diminui o contador. Abaixo está um trecho de um segmento de lista de discussão onde descrevo alguns cenários em que ele falha.

Atualização 2: Doutrina DBAL também tem esse recurso. Eles chamam isso de Aninhamento de Transação.

Goste ou não, as transações são "globais" e não obedecem ao encapsulamento orientado a objetos.

Cenário de problema nº 1

Eu chamo commit() , minhas alterações estão confirmadas? Se estou executando dentro de uma "transação interna", eles não estão. O código que gerencia a transação externa poderia optar por reverter e minhas alterações seriam descartadas sem meu conhecimento ou controle.

Por exemplo:
  1. Modelo A:iniciar a transação
  2. Modelo A:execute algumas alterações
  3. Modelo B:iniciar a transação (sem operação silenciosa)
  4. Modelo B:execute algumas alterações
  5. Modelo B:confirmação (sem operação silenciosa)
  6. Modelo A:reversão (descarta tanto as alterações do modelo A quanto as alterações do modelo B)
  7. Modelo B:WTF!? O que aconteceu com minhas alterações?

Cenário de problema nº 2

Uma transação interna é revertida, ela pode descartar alterações legítimas feitas por uma transação externa. Quando o controle é devolvido ao código externo, ele acredita que sua transação ainda está ativa e disponível para ser confirmada. Com seu patch, eles podem chamar commit() , e como o transDepth agora é 0, ele definiria silenciosamente $transDepth para -1 e retornar true, depois de não confirmar nada.

Cenário de problema nº 3

Se eu chamar commit() ou rollback() quando não há transação ativa, ele define o $transDepth para -1. O próximo beginTransaction() incrementa o nível para 0, o que significa que a transação não pode ser revertida nem confirmada. Chamadas subsequentes para commit() apenas diminuirá a transação para -1 ou mais, e você nunca poderá confirmar até fazer outro beginTransaction() supérfluo para aumentar o nível novamente.

Basicamente, tentar gerenciar transações na lógica do aplicativo sem permitir que o banco de dados faça a contabilidade é uma ideia condenada. Se você tiver um requisito para que dois modelos usem controle de transação explícito em uma solicitação de aplicativo, deverá abrir duas conexões de banco de dados, uma para cada modelo. Em seguida, cada modelo pode ter sua própria transação ativa, que pode ser confirmada ou revertida independentemente uma da outra.