Problema de invalidação @Transactional quando diferentes métodos do mesmo tipo chamam uns aos outros

Este artigo tem como objetivo explorar o impacto das chamadas de métodos mútuos na validade das anotações de transação do Spring na mesma classe.

suponha

A classe A possui dois métodos, a e b:
o método a é modificado por public e o método b será chamado quando for executado;
o método b é modificado por private e operará no banco de dados quando for executado.

Cenas

cena 1

O método a chama o método b, o método a não tem decoração de anotação de transação, neste momento, não importa se o método b tem decoração de anotação de transação ou não, a transação será inválida;

cena 2

O método a chama o método b e o método a é decorado com anotações de transação, então a transação do método a entrará em vigor e a exceção lançada no método b também será revertida. Neste momento, se o método b estiver decorado com anotações de transação, a transação do método b se tornará inválida.

Análise de causa

Ao chamar métodos de outras classes de fora, se o método de destino for modificado com a anotação da transação, quando o spring varrer o bean, ele gerará uma classe de proxy agrupada para o método contendo @Transactional e usará o AOP para iniciar a transação antes do método é executado. Transações de confirmação/reversão após a execução. No entanto, as chamadas de método entre as classes não seguem essa lógica, portanto, não haverá objetos proxy e as transações não serão iniciadas.

Solução

  1. Adicione a transação do método pai: quando o método a na classe A chama o método b, as anotações podem ser adicionadas a a para gerenciar as transações comuns do método a e do método b.
  2. Use transações programáticas em métodos:
//引入事务模板
@Autowired
TransactionTemplate transactionTemplate;

//在b方法(被调方法)中使用模板创建并执行语句
transactionTemplate.execute((TransactionCallback<Void>) status -> {
    
    
	// 业务逻辑
	return null;
})
  1. Obtenha o objeto proxy da classe atual, use o objeto proxy para chamar o método b
    • Injete-se e use o objeto injetado para chamar o método b
    • Obtenha a classe de proxy atual por meio do contexto de primavera, use a classe de proxy para chamar o método b
    • Use AopContext para obter a classe proxy atual, use a classe proxy para chamar o método b

extensão

A lógica das chamadas de método entre diferentes classes

O método a da classe A chama o método b da classe B, desde que o método a ou b esteja configurado com uma transação, a transação terá efeito neste momento.
Se ambos os métodos forem configurados com transações, a forma como as duas transações serão propagadas dependerá das características de propagação da transação configuradas. O método padrão das transações spring é OBRIGATÓRIO (juntar se houver transação, criar se não houver transação), neste caso, se ambos os métodos a e b estiverem anotados com @Transactional, porque a chama b, então o método b será adicionado a um método executado na transação.

recurso de propagação de transação de primavera

REQUERIDO (o tipo de propagação de transação padrão do Spring é necessário: precisa, depende de, depende de): Se não houver transação no momento, crie você mesmo uma nova transação, se houver uma transação no momento, junte-se a esta transação Quando A chamar B: se não houver transação em A,
B Se houver uma transação em A, então B criará uma nova transação; se houver uma transação em A e houver uma transação em B, então B se juntará a A e se tornará uma transação. , todos são bem-sucedidos ou ambos falham. (Se houver 2 SQLs em A e 2 SQLs em B, esses quatro SQLs se tornarão um SQL, todos serão bem-sucedidos ou todos falharão)

SUPPORTS (supports: support; support): Existe atualmente uma transação, então junte-se à transação atual, se não houver transação, ela será executada em um método não transacional Se houver uma transação em A, então a transação
do O método B será adicionado à transação A para se tornar uma transação (sucesso conjunto, falha conjunta), se não houver transação em A, então B será executado em um modo não transacional (commit diretamente após a execução);

OBRIGATÓRIO (obrigatório: obrigatório): Se houver uma transação atual, junte-se à transação atual e, se a transação atual não existir, uma exceção será lançada.
Se houver uma transação em A, a transação do método B é adicionada à transação de A para se tornar uma transação (sucesso junto, falha conjunta); se não houver transação em A e houver transação em B, então B irá lançar diretamente uma exceção, o que significa que B deve executar dentro de uma transação para suportar a reversão

REQUIRES_NEW (requer_novo: requer novo): Crie uma nova transação, se houver uma transação atual, suspenda a transação.
B criará uma nova transação e as transações A e B não interferirão uma na outra.Quando eles tiverem problemas e reverterem, eles reverterão apenas suas próprias transações;

NOT_SUPPORTED (não suportado: não suportado): Executado de maneira não transacional. Se houver uma transação no momento, o
callee B suspenderá a transação atual e executará de maneira não transacional (enviar diretamente). Transação, A será suspenso (não executado, espere B terminar a execução, retorne); A e B têm uma exceção e precisam reverter, sem afetar um ao outro

NEVER (nunca: nunca): Se nenhuma transação existir no momento, ela será executada de maneira não transacional; se houver, uma exceção será lançada. Ou seja, B nunca é executado de maneira transacional.
A não pode ter uma transação. Se não, B será executado de maneira não transacional. Se A tiver uma transação, uma exceção será lançada diretamente.

NESTED (nested: nested) transação aninhada: Se a transação atual existir, ela será executada na transação aninhada, caso contrário a operação de REQUIRED é a mesma (abrir uma transação)
Se não houver transação em A, então B cria uma transação para executar, se A também houver uma transação nele, então B irá aninhar a transação nele

artigo de referência

https://blog.csdn.net/ChineseSoftware/article/details/127602310
https://blog.csdn.net/single_0910/article/details/121561725
https://blog.csdn.net/dayuiicghaid/article/details/ 125260092
https://blog.csdn.net/hellozhxy/article/details/109753711

Acho que você gosta

Origin blog.csdn.net/Ka__ze/article/details/131087408
Recomendado
Clasificación