2015-10-22 20 views
7

In caso di propagazione REQUIRED quando il metodo del chiamante è transazionale, il metodo corrente sostituisce le proprietà della transazione che racchiudono (ad esempio rollbackFor) se sono diverse?Spring @Transactional Annotation proprietà precedenza/ereditarietà

dell'illustrazione:

Class A { 
    @Transactional(propagation = Propagation.REQUIRED, 
     rollbackFor = { SomeException.class}) 
    void foo() { 
     try { 
      b.bar(); 
     } catch (OtherException e) { 
      // is the transaction marked as rollback-only at this point ? 
     } 
    } 
} 

Class B { 
    @Transactional(propagation = Propagation.REQUIRED, 
     rollbackFor = { OtherException.class}) 
    void bar() { 
     [...] 
    } 
} 

modificare:

Bene, vorrei evitare di banale di risposte scope, quindi cerchiamo di essere chiari, I'am a conoscenza di movimentazione primavera propagazione.

Se non lo sei, qui di seguito è la parte rilevante della documentazione, Vorrei solo chiarire la prima parte per quanto riguarda il mio esempio di sopra:

PROPAGATION_REQUIRED

Quando l'impostazione di propagazione è PROPAGATION_REQUIRED , viene applicato un ambito di transazione logico per ogni metodo su cui viene applicata l'impostazione applicata. Ciascun ambito di transazione logico di questo tipo può determinare lo stato di solo rollback , con uno scope di transazione esterno indipendente logicamente dall'ambito della transazione interna. Del corso , in caso di comportamento standard PROPAGATION_REQUIRED, tutti questi ambiti verranno associati alla stessa transazione fisica. Pertanto, un marcatore di rollback impostato nell'ambito della transazione interna influisce sulla possibilità della transazione esterna di effettuare effettivamente il commit (come ci si aspetterebbe da ) a .

Tuttavia, nel caso in cui un ambito di transazione interna imposta il rollback-unico marcatore, la transazione esterna non ha deciso il rollback in sé, e così il rollback (silenziosamente innescata dalla interna ambito della transazione) è inaspettato . A tale punto viene generata una UnexpectedRollbackException corrispondente. Questo è il comportamento previsto in modo che il chiamante di una transazione non può mai essere ingannato a presumere che un commit è stato eseguito quando in realtà non lo era. Quindi, se una transazione interna (di cui il chiamante esterno non è a conoscenza) in modo invisibile contrassegna una transazione come solo rollback, il chiamante esterno chiama ancora commit. Il chiamante esterno deve ricevere un valore UnexpectedRollbackException per indicare chiaramente che è stato eseguito un rollback .

La mia domanda può essere riformulata come questo:

L'ambito transazione logica detiene le proprietà di transazione?

+0

È possibile fare riferimento http://stackoverflow.com/questions/ 8490852/spring-transactional-isolation-propagation/32223597 # 32223597 per propagazione diversa con più scenari –

risposta

1

Quindi, ho impostato un test case, la risposta breve è sì.

L'ambito logico della transazione contiene le proprietà della transazione e i suoi limiti sono effettivamente quelli del metodo annotato.

Quindi, anche se la transazione fisica sottostante è la stessa per entrambi i metodi, le proprietà logiche sono appropriate per ogni metodo e il metodo interno può forzare il rollback della transazione del metodo esterno. Se quest'ultimo attiva un commit, tuttavia porterà a UnexpectedRollbackException.

cf. Primavera TransactionInterceptor (commenti sono miei)

try { 
     retVal = invocation.proceed(); 
} 
catch (Throwable ex) { 
     completeTransactionAfterThrowing(txInfo, ex); 
     throw ex; 
} 

completeTransactionAfterThrowing():

// txinfo is proper to the invocation target method 
if (txInfo.transactionAttribute.rollbackOn(ex)) { 
      try { 
       txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); 
      } 

AbstractPlatformTransactionManager.processRollback():

else if (status.isNewTransaction()) { //requiresnew 
    doRollback(status); 
} 
else if (status.hasTransaction()) { //requiered 
     [...] 
     doSetRollbackOnly(status); 
    } 
} 
+0

NOTA: se si usa un debugger non si ha fiducia nello stato della variabile interna, chiamare esplicitamente il getter TransactionAspectSupport.currentTransactionStatus(). IsRollbackOnly() – Gab

0

Vedere la sezione 16.5.7 di spring documentation. Anche se i metodi interni sono annotati con REQUIRED quando vengono chiamati all'interno del contesto della transazione, verranno mappati sulla stessa transazione fisica.

+1

Siamo spiacenti ma non rispondete domanda. – Gab

0

Nella mia comprensione delle specifiche, direi in questo esempio:

Class A { 
    @Transactional(propagation = Propagation.REQUIRED, 
     rollbackFor = { SomeException.class}) 
    void foo() { 
     try { 
      b.bar(); 
     } catch (OtherException e) { 
      // the transaction is marked as rollback-only by the inner call as it thrown an OtherException 
      // XXX --- or not if inner logical scope does not handle overridden property 'rollbackFor' ? --- 
      // anyway, we avoid UnexpectedRollbackException by enforcing physical rollback to outter scope programmatically, by throwing : 
      throw new SomeExeption(e); 
     } 
    } 
} 

Class B { 
    @Transactional(propagation = Propagation.REQUIRED, 
     rollbackFor = { OtherException.class}) 
    void bar() { 
     [...] 
    } 
} 

in modo che possiamo riformulare la questione: non override proprietà "rollbackFor" è gestita da interno gestione logica ambito di transazione?

A proposito, qual è la classe e la versione del gestore transazioni esatto che utilizzate?