transaction manager example driven data bean annotation java spring transactions

java - manager - transaction spring data



Comenzando una nueva transacción en Spring bean (3)

Tenemos:

@Transactional(propagation = Propagation.REQUIRED) public class MyClass implementes MyInterface { ...

MyInterface tiene un solo método: go() .

Cuando se ejecuta go (), iniciamos una nueva transacción que se confirma / deshace cuando se completa el método. Esto está bien.

Ahora digamos que en go () llamamos a un método privado en MyClass que tiene @Transactional(propagation = Propagation.REQUIRES_NEW . Parece que Spring "ignora" la anotación REQUIRES_NEW y no inicia una nueva transacción. Creo que esto se debe a que Spring AOP opera en el nivel de la interfaz (MyInterface) y no intercepta ninguna llamada a los métodos de MyClass. ¿Es correcto?

¿Hay alguna forma de iniciar una nueva transacción dentro de la transacción go ()? ¿Es la única forma de llamar a otro bean administrado Spring que tiene transacciones configuradas como REQUIRES_NEW?

Actualización : agregando que cuando los clientes ejecutan go() lo hacen a través de una referencia a la interfaz, no a la clase:

@Autowired MyInterface impl; impl.go();


De la referencia de primavera 2.5:

Cuando se usan proxies, la anotación @Transactional solo debe aplicarse a métodos con visibilidad pública. Si @Transactional anotaciones con métodos protegidos, privados o visibles con la anotación @Transactional , no se generará ningún error, pero el método anotado no mostrará la configuración transaccional configurada.

Así que Spring ignora la anotación @Transactional en métodos no públicos.

También,

En el modo proxy (que es el valor predeterminado), solo se interceptarán las llamadas a métodos "externos" que lleguen a través del proxy. Esto significa que ''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 !

Entonces, incluso si hace public su método, llamarlo desde un método de la misma clase no iniciará una nueva transacción.

Puede usar el modo aspectj en la configuración de la transacción para que el código relacionado con la transacción se entrelace en la clase y no se cree un proxy en el tiempo de ejecución.

Vea el documento de referencia para más detalles.

Otra forma posible de hacer esto es obtener el proxy de primavera de la clase en la propia clase y llamar a los métodos en lugar de this :

@Service @Transactional(propagation = Propagation.REQUIRED) public class SomeService { @Autowired private ApplicationContext applicationContext; private SomeService getSpringProxy() { return applicationContext.getBean(this.getClass()); } private void doSomeAndThenMore() { // instead of // this.doSometingPublicly(); // do the following to run in transaction getSpringProxy().doSometingPublicly(); } public void doSometingPublicly() { //do some transactional stuff here } }


En resumen, debe llamar al método a través de proxy para lograr el comportamiento transaccional. Es posible llamar a "REQUIRES_NEW" en el mismo bean, como se pregunta en la pregunta. Para hacer eso tienes que hacer una referencia "yo". En primavera no es posible. Hay que inyectarlo con la anotación @Resource.

@Service("someService") public class ServieImpl implements Service { @Resource(name = "someService") Service selfReference; @Transactional public void firstMethod() { selfReference.secondMethod(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void secondMethod() { //do in new transaction } }

La invocación en firstMethod llama al proxy y no a "esto", lo que debería hacer que la transacción "REQUIRES_NEW" funcione.


@Transactional solo se notará si está en un método public , debido a la forma en que funciona Spring AOP.

Sin embargo, puede iniciar una nueva transacción mediante programación si lo desea, utilizando TransactionTemplate , por ejemplo,

TransactionTemplate txTemplate = new TransactionTemplate(txManager); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); txTemplate.execute(new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus status) { // do stuff } });