De http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
A recomendação da equipe do Spring é que você anote apenas classes concretas com a @Transactional
anotação, ao invés de anotar interfaces. Você certamente pode colocar a @Transactional
anotação em uma interface (ou um método de interface), mas isso só funcionará como você esperaria se estiver usando proxies baseados em interface. O fato de as anotações não serem herdadas significa que se você estiver usando proxies baseados em classe, as configurações de transação não serão reconhecidas pela infraestrutura de proxy baseada em classe e o objeto não será empacotado em um proxy transacional (o que seria decididamente ruim ) . Portanto, siga o conselho da equipe do Spring e anote apenas classes concretas (e os métodos de classes concretas) com a @Transactional
anotação.
Observação: como esse mecanismo é baseado em proxies, apenas chamadas de método 'externas' que chegam por meio do proxy serão interceptadas. Isso significa que a 'auto-invocação', ou seja, um método dentro do objeto de destino chamando algum outro método do objeto de destino, não levará a uma transação real em tempo de execução, mesmo se o método invocado estiver marcado com @Transactional
!
(Ênfase adicionada à primeira frase, outra ênfase do original.)
JdkDynamicAopProxy
passa por todos os orientadores de bean em cada chamada de método (consulte tambémDefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()
), que no caso de configuração de transação declarativa, incluiBeanFactoryTransactionAttributeSourceAdvisor
. Por sua vez,TransactionAttributeSourcePointcut#matches()
é invocado, que deve coletar as informações relativas à transação. É passada a classe de destino e sempre pode atravessar todas as interfaces que esta classe implementa. Agora: por que isso não pode não funcionar de forma confiável?@Transactional
anotações herdadas se aplicaria? Portanto, embora seja possível , não culpo Spring. jira.springsource.org/browse/SPR-975Você pode colocá-los na interface, mas esteja avisado que as transações podem não acontecer em alguns casos. Veja a segunda dica na seção 10.5.6 dos documentos do Spring:
Eu recomendaria colocá-los na implementação por esse motivo.
Além disso, para mim, as transações parecem um detalhe de implementação, portanto, devem estar na classe de implementação. Imagine ter implementações de wrapper para log ou implementações de teste (simulações) que não precisam ser transacionais.
fonte
A recomendação do Spring é que você anote as implementações concretas em vez de uma interface. Não é incorreto usar a anotação em uma interface, é apenas possível usar indevidamente esse recurso e inadvertidamente ignorar sua declaração @Transaction.
Se você marcou algo transacional em uma interface e depois se referiu a uma de suas classes de implementação em outro lugar no spring, não é muito óbvio que o objeto que o spring cria não respeitará a anotação @Transactional.
Na prática, é mais ou menos assim:
public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} }
fonte
Apoiando @Transactional nas classes concretas:
Eu prefiro arquitetar uma solução em 3 seções geralmente: uma API, uma Implementação e uma Web (se necessário). Eu tento o meu melhor para manter a API o mais leve / simples / POJO possível, minimizando as dependências. É especialmente importante se você jogar em um ambiente distribuído / integrado onde você precisa compartilhar muito as APIs.
Colocar @Transactional requer bibliotecas Spring na seção API, que IMHO não é eficaz. Portanto, prefiro adicioná-lo na Implementação onde a transação está sendo executada.
fonte
Colocá-lo na interface não tem problema, desde que todos os implementadores previsíveis de seu IFC se importem com os dados TX (transações não são problemas com os quais apenas bancos de dados lidam). Se o método não se importa com TX (mas você precisa colocá-lo lá para Hibernate ou qualquer outra coisa), coloque-o no impl.
Além disso, pode ser um pouco melhor colocar
@Transactional
os métodos na interface:public interface FooService { @Transactional(readOnly = true) void doSmth(); }
fonte