De http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
La recomendación del equipo de Spring es que solo anote clases concretas con la @Transactional
anotación, en lugar de anotar interfaces. Ciertamente puede colocar la @Transactional
anotación en una interfaz (o un método de interfaz), pero esto solo funcionará como lo esperaría si está utilizando proxies basados en interfaz. El hecho de que las anotaciones no se hereden significa que si está utilizando proxies basados en clases, la infraestructura de proxys basados en clases no reconocerá la configuración de la transacción y el objeto no se incluirá en un proxy transaccional (lo que sería definitivamente malo ) . Así que, por favor, siga el consejo del equipo de Spring y solo anote las clases concretas (y los métodos de las clases concretas) con la @Transactional
anotación.
Nota: Dado que este mecanismo se basa en proxies, solo se interceptarán las llamadas a métodos "externos" que ingresen a través del proxy. Esto significa que la 'auto-invocación', es decir, un método dentro del objeto de destino que llama a otro método del objeto de destino, no conducirá a una transacción real en tiempo de ejecución, incluso si el método invocado está marcado con @Transactional
!
(Énfasis agregado a la primera oración, otro énfasis del original).
JdkDynamicAopProxy
pasa por todos los asesores de beans en cada invocación de método (ver tambiénDefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()
), que en caso de configuración de transacción declarativa, incluyeBeanFactoryTransactionAttributeSourceAdvisor
. A su vezTransactionAttributeSourcePointcut#matches()
se invoca, que debe recoger la información relativa a la transacción. Se pasa a la clase de destino y siempre puede atravesar todas las interfaces que implementa esta clase. Ahora: ¿por qué esto no puede funcionar de manera confiable?@Transactional
anotaciones heredadas se aplicaría? Entonces, aunque todo es posible , no culpo a Spring. jira.springsource.org/browse/SPR-975Puede ponerlos en la interfaz, pero tenga en cuenta que es posible que las transacciones no terminen ocurriendo en algunos casos. Vea el segundo consejo en la Sección 10.5.6 de los documentos de Spring:
Recomendaría ponerlos en la implementación por este motivo.
Además, para mí, las transacciones parecen un detalle de implementación, por lo que deberían estar en la clase de implementación. Imagínese tener implementaciones de contenedor para el registro o implementaciones de prueba (simulacros) que no necesitan ser transaccionales.
fuente
La recomendación de Spring es que anote las implementaciones concretas en lugar de una interfaz. No es incorrecto usar la anotación en una interfaz, simplemente es posible hacer un mal uso de esa función y omitir inadvertidamente su declaración de @Transaction.
Si ha marcado algo transaccional en una interfaz y luego se refiere a una de sus clases de implementación en otro lugar en la primavera, no es muy obvio que el objeto que crea Spring no respetará la anotación @Transactional.
En la práctica, se parece a esto:
public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} }
fuente
Apoyando a @Transactional en las clases concretas:
Prefiero diseñar una solución en 3 secciones generalmente: una API, una Implementación y una Web (si es necesario). Hago todo lo posible para mantener la API lo más ligera / simple / POJO posible minimizando las dependencias. Es especialmente importante si lo juegas en un entorno distribuido / integrado donde tienes que compartir mucho las API.
Poner @Transactional requiere bibliotecas Spring en la sección API, que en mi humilde opinión no es efectivo. Entonces prefiero agregarlo en la Implementación donde se está ejecutando la transacción.
fuente
Ponerlo en la interfaz está bien siempre que todos los implementadores previsibles de su IFC se preocupen por los datos TX (las transacciones no son problemas que solo tratan las bases de datos). Si al método no le importa TX (pero necesita ponerlo allí para Hibernate o lo que sea), colóquelo en el impl.
Además, podría ser un poco mejor colocar
@Transactional
los métodos en la interfaz:public interface FooService { @Transactional(readOnly = true) void doSmth(); }
fuente