2012-03-29 24 views
14

que tienen un conjunto de @Service granos que heredan funcionalidad básica de una clase abstracta. Marqué cada uno de los servicios de subclase concretos con @Service y @Transactional. La superclase abstracta contiene el método de punto de entrada público para cada uno de estos servicios. En otras palabras, tengo algo similar a lo siguiente:reglas de herencia primavera @Transactional

abstract class AbstractService { 

    public void process() { 
     // Do common initialisation code here 
     processSpecific(); 
     // Do common completion code here 
    } 

    abstract protected void processSpecific(); 
} 


@Service @Transactional 
public class FirstSpecificService extends AbstractService { 
    protected void processSpecific() { 
     // Do specific processing code here 
    } 
} 


@Service @Transactional 
public class SecondSpecificService extends AbstractService { 
    protected void processSpecific() { 
     // Do different specific processing code here 
    } 
} 

El código específico en cada servicio subclase concreta hace varias llamadas a la capa DAO para realizar cambios en la base de datos, que tienen REQUIRED como la propagación transaccional tipo.

Ahora, con los servicios definidos anteriormente, descubrí que no había ninguna transacción actual dentro del código de estos servicios concretos de subclase, y cada llamada a la capa DAO estaba creando una nueva transacción, haciendo los cambios, comprometer la transacción y regresar.

Sin embargo, si anoto la super-clase abstracta con @Transactional, a continuación, una transacción es creado correctamente, y los sub-llamadas a la capa DAO todos participan en la transacción actual.

Así que mi pregunta es, ¿cuáles son las reglas para heredar el comportamiento @Transactional? ¿Por qué Spring no usa el @Transactional en los servicios de subclase concretos que en realidad está creando instancias? ¿El @Transactional necesita estar en la superclase en este caso porque ahí es donde se encuentra el método de punto de entrada público?

+0

Por cierto, he echado un vistazo a la [documentación relevante de SpringSource] (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework -reference.html # transaction-declarative-annotations), pero eso no parece cubrir esto. – DuncanKinnear

Respuesta

9

A partir de la documentación de la operación de primavera,

Nota: En el modo de proxy (que es el valor por defecto), único método 'externo' las llamadas entrantes a través del proxy será interceptada. Esto significa que 'auto-invocación', es decir, un método en el objeto de destino llamando a algunos otro método del objeto de destino, no dará lugar a una transacción real en tiempo de ejecución, incluso si el método invocado está marcado con @Transactional!

A pesar de que usted tiene la @Transactional en su aplicación concreta y que está llamando método de proceso que en realidad es transaccional por su anotación, pero el método de proceso llamando processSpecific en su subclase no es transaccional debido a esta llamada interna.

Mira en el tejido.

+0

¿Pero no será el proxy una instancia de 'FirstSpecificService'? En ese caso, el sistema llamará al método de 'proceso' externo de esa instancia, y la instancia en sí misma se marcará como '@ Transactional'. Entiendo completamente que los métodos internos privados o protegidos que están marcados como '@ Transactional' no afectarán la transacción, pero eso no es lo que tengo. Mi frijol entero está marcado como '@ Transactional'. – DuncanKinnear

+0

No, no será transaccional si se llama desde el método interno. Para empezar cuando llama al método de proceso desde externo, la instancia de proxy se controla mediante transacción y cuando el método de proceso llama processSpecific, spring no sabe acerca de la transacción ya que el corte de punto se realizó en el objeto proxy no en el proceso de subclaseSpecific método. Tuvimos el mismo problema y agregamos el tiempo de carga tejiendo y todo funcionó. – Kathir

+0

Cabina a la que explica 'carga el tiempo de tejido' con respecto a mi ejemplo anterior. ¿Cómo cambiaría el código de estos servicios de ejemplo (artificiales)? – DuncanKinnear

1

¿Has leído la parte sobre transaction propagation y cómo se puede configurar usando @Transactional?

Otra área de interés es que la primavera recomienda que usted debe annotate concrete classes (como se opone para anotar las interfaces).

+0

Sí, como se indicó anteriormente, he leído todas esas secciones de la documentación y ninguna de ellas parecía aplicarse en este caso. Mi superclase abstracta es ** no ** una interfaz, es un código heredado por la subclase concreta real. Quizás podría citar la sección de la documentación que cree que se aplica a mi ejemplo. – DuncanKinnear

+1

Si desea asegurarse de que sus DAO siempre participen en una transacción existente (iniciada por su servicio) debe configurar los DAO para que sean @Transactional (propagation = [Propagation.MANDATORY] (http://static.springsource.org) /spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/Propagation.html#MANDATORY)), porque al usar [REQUERIDO] (http://static.springsource.org/spring/docs/3.1 .x/javadoc-api/org/springframework/transaction/annotation/Propagation.html # REQUIRED) creará una nueva transacción si no existe ninguna. – matsev

+0

Sí, esa sería una forma de detectar estos problemas en el futuro, pero aún no explica cuáles son las reglas de herencia. – DuncanKinnear

Cuestiones relacionadas