2015-10-22 4 views
7

Im Fall von REQUIRED Propagierung, wenn die Aufrufer-Methode selbst transactional ist, überschreibt die aktuelle Methode umgebende Transaktionseigenschaften (zum Beispiel rollbackFor), wenn sie unterschiedlich sind?Spring @Transactional Annotation Eigenschaften Vorrang/Vererbung

Illustration:

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() { 
     [...] 
    } 
} 

bearbeiten:

Nun möchte Ich mag out of scope Antworten zu vermeiden, trivial, also lassen Sie uns klar sein, Ich bin bewusst Federausbreitungs Handhabung.

Wenn Sie nicht, unten ist der relevante Teil der Dokumentation, ich möchte nur den ersten Teil in Bezug auf meinem obigen Beispiel verdeutlichen:

PROPAGATION_REQUIRED

Wenn die Ausbreitungseinstellung ist PROPAGATION_REQUIRED wird für jede Methode, für die die Einstellung gilt, ein logischer Transaktionsbereich angelegt. Jeder dieser logischen Transaktionsbereiche kann den Rollback-Only-Status einzeln bestimmen, wobei der äußere Transaktionsbereich logisch vom inneren Transaktionsbereich unabhängig ist. Natürlich werden von im Falle des Standardverhaltens PROPAGATION_REQUIRED alle diese Bereiche der gleichen physischen Transaktion zugeordnet. Ein Rollback-Only-Marker, der im inneren Transaktionsbereich festgelegt ist, wirkt sich also auf die Chance der äußeren Transaktion aus, tatsächlich zu committen (wie Sie erwarten würden es zu).

Jedoch in dem Fall, in dem ein inneren Transaktionsbereich setzt den Rollback-only-Marker, die äußeree Transaktion auf dem Rollback mich nicht entschieden, und so die Rollback (geräuschlos durch den inneren Transaktionsbereich ausgelöst) ist unerwartet . Eine entsprechende UnexpectedRollbackException wird an diesem Punkt ausgelöst. Dies wird Verhalten erwartet, so dass der Aufrufer einer Transaktion nie zu getäuscht werden kann davon ausgehen, dass ein Commit durchgeführt wurde, wenn es wirklich nicht war. Wenn also eine innere Transaktion (von der der äußere Aufrufer nicht Kenntnis hat) stillschweigend eine Transaktion als Rollback-only markiert, ruft der äußere Aufrufer immer noch commit auf. Der äußere Aufrufer muss UnexpectedRollbackException erhalten, um deutlich anzuzeigen, dass stattdessen ein Rollback ausgeführt wurde.

Meine Frage kann als diese neu gefasst:

Ist die logische Transaktionsbereich die Transaktionseigenschaften hält?

+0

Sie verweisen http://stackoverflow.com/questions/ 8490852/spring-transactional-isolation-propagation/32223597 # 32223597 für verschiedene Propagierungen mit mehreren Szenarien –

Antwort

1

Also habe ich einen Testfall eingerichtet, die kurze Antwort ist ja.

Der logische Bereich der Transaktion enthält die Transaktionseigenschaften und seine Grenzen sind in der Tat die mit der Annotation versehenen Methoden.

Auch wenn die zugrunde liegende physische Transaktion für beide Methoden gleich ist, sind die logischen Eigenschaften für jede Methode geeignet, und die innere Methode kann so das Rollback der äußeren Methodentransaktion erzwingen. Wenn dieser Befehl zuletzt einen Commit auslöst, führt dies zu einer UnexpectedRollbackException.

vgl. Frühling TransactionInterceptor (Kommentare sind Mine)

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: Wenn Sie einen Debugger verwenden, vertrauen Sie dem internen Variablenstatus nicht explizit, rufen Sie den getter TransactionAspectSupport.currentTransactionStatus() explizit auf. IsRollbackOnly() – Gab

0

Siehe Abschnitt 16.5.7 von spring documentation. Auch wenn innere Methoden mit REQUIRED kommentiert werden, wenn sie im Transaktionskontext aufgerufen werden, wird sie derselben physischen Transaktion zugeordnet.

+1

Sorry, aber Sie beantworten nicht die Frage. – Gab

0

In meinem Verständnis der Spezifikationen, würde ich in diesem Beispiel sagen:

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() { 
     [...] 
    } 
} 

So können wir die Frage umformulieren: nicht außer Kraft gesetzt „rollbackFor“ Eigenschaft durch inneres logisches Transaktionsbereich Management gehandhabt wird?

Übrigens, was ist die genaue Transaktionsmanager-Klasse und Version, die Sie verwenden?