2010-08-26 19 views
7

Estoy utilizando la gestión de transacciones con Spring e Hibernate. Mi situación es la siguiente:
Tengo frijol Un que está rodeada de transacción y se llama frijol B que se define con la transacción que incluye el atributo 'PROPAGATION_REQUIRED'Problema de propagación de la transacción de primavera

B en este caso doesn' t abrir una transacción nueva pero usa la existente (ver en los registros: 'Participar en una transacción existente'). Sin embargo, en caso de que el método en B genere una excepción runtimeException, en su camino de regreso a A ensuciará la transacción y causará que se marque para retroceder, incluso si el método externo de A captará la excepción y no lo hará. tirar a la basura. Creo que este comportamiento es incorrecto, en este caso deseo que A controle la transacción y B no debe interrumpir la transacción en ningún caso.
¿Hay alguna manera de definir B para abrir la transacción si no se definió ninguna transacción pero NO HACER NADA si ya está dentro de una transacción existente y dejar que el nivel superior tome la decisión de confirmar o revertir?

Consulte más respuestas sobre este tema en un hilo en Spring community here.

Respuesta

1

Teóricamente es posible, pero no dentro de los medios estándar de los aspectos de Transacciones de Spring. Debería crear su propio aspecto que duplique la funcionalidad estándar de primavera, ampliándola para su caso especial. Quizás incluso sea posible extender el aspecto original que usan.

(. Probablemente tendrá que definir una anotación personalizada sin embargo, porque no se puede anular el atributo @Transactional ni extender la enumeración de propagación)

Éstos son algunos consejos:

Además, se debe considerar la lectura del libro AspectJ in Action, incluso si sólo desea utilizar la primavera AOP, ya que da una muy buena visión.

Un buen punto de partida es descargar el sources of the spring-aspects jar, ver lo que están haciendo allí y proporcionan su propia extensión de cualquiera org.springframework.transaction.aspectj.AbstractTransactionAspect o org.springframework.transaction.aspectj.AnnotationTransactionAspect

Para resumir: Estoy seguro de que se puede hacer, pero tomará mucho trabajo. La Spring Transaction API es bastante buena, aunque así es. Tal vez deberías aprender a vivir con sus limitaciones. De lo contrario: comience a piratear (ver arriba)

+0

Lo que está diciendo es que no hay una solución lista para usar. Todavía intentaré buscar una solución más genérica que requiera menos trabajo, antes marque esta respuesta como la mejor. – Spiderman

+0

seguro, no hay necesidad de elegir la respuesta correcta dentro de una hora de la pregunta. Pero un voto positivo sería bueno :-) –

+0

Para cerrar este caso, creo que ninguna solución se ajusta a mis solicitudes. Por lo tanto, este comportamiento por diseño de Spring me parece una limitación. La única solución real es anular la implementación de Spring como se sugiere aquí. – Spiderman

0

¿Quizás usar la anotación @Transactional de la manera que se muestra a continuación resolverá su problema? @Transactional (propagation = Propagation.REQUIRED, noRollbackFor = RuntimeException.class)

+0

no es bueno porque en caso de que B se llame NO desde A pero desde otro lugar fuera, quiero que el método de llamada a B se envuelva con una transacción y que en el caso de runtimeException lo haga. – Spiderman

+0

@Spiderman: ¿Por qué no utilizar dos puntos de entrada para su lógica: el primero que se llama desde el bean 'A' (' @Transactional (propagation = ..., noRollbackFor = ...) void myMethodSafe() 'y el segundo uno para ser llamado desde cualquier otro lugar ('@Transactional (propagation = ...) void myMethod()'). Sí, dos métodos en la interfaz, ¿por qué no?Alternativamente, puede tener un método de interfaz y un indicador adicional 'boolean noRollbackForException', que se establece en' true' cuando el método se invoca desde bean 'A' y luego' try/catch' la excepción necesaria (cuando se establece en 'false' la excepción se arroja más lejos). –

0

Una solución es proporcionar DOS definiciones de bean en su context.xml.

  • Uno con PROPAGATION_REQUIRED que va a utilizar cuando se desea el grano sea transaccional sí

  • El segundo con PROPAGATION_SUPPORTS que va a utilizar cuando se llama el grano desde el interior de una transacción existente (En realidad, incluso podría ser no transaccional).

Si desea minimizar la duplicación, puede factorizar la configuración común en una definición de bean padre.

4

Parece que Propagation.NESTED es algo que puede ayudarle a:

  • Si B falla, la operación comenzó con A (y continuaron con B) será retrotraído correctamente al punto de rescate antes de B se llama sin tocar A.
  • Cuando se confirma B, solo se libera el punto de seguridad, no se emite nada más a DB. Bascailly significa que los cambios realizados por B se "fusionan" en la transacción A.
  • Después de B acabados, en cualquier caso antes mencionado A puede decidir el tiempo de seguir y comprometerse (que serán un verdadero comprometen a DB que incluirá todos los cambios por A y B [si se ha comprometido]) o para deshacer (que la voluntad restituir la transacción hasta el estado en que se creó, invalidando todos los cambios por A + B).
+0

Propagation.NESTED no me ayudará. Porque si B se terminará normalmente y luego las palabras posteriores, la última parte de A arrojará una excepción, y no se retrotraerá también a B, aunque esta es mi intención. – Spiderman

+0

@Spiderman: No, lo hará. He actualizado mi respuesta con una descripción más detallada del escenario. Intentalo :) –

4

Al configurar el administrador de transacciones primavera, se puede establecer la propiedad denominada "globalRollbackOnParticipationFailure". Si se establece en falso, una excepción que ocurra en un método que participa en una transacción existente no marcará la transacción para la reversión. La transacción solo está marcada para reversión si la excepción se elimina del método que inició la transacción.

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
    <property name="globalRollbackOnParticipationFailure" value="false" /> 
</bean> 

Consulte el JavaDoc para obtener más información.

Cuestiones relacionadas