2009-11-09 15 views
9

Methoden aufgerufen:
1. Struts Aktion
2. Service-Klasse-Methode (von @Transactional kommentierten)
3. Xfire webservice AnrufWie kann verhindert werden, dass JPA Transaktionen rückgängig macht?

Alles inklusive Streben (DelegatingActionProxy) und Transaktionen mit Feder konfiguriert ist.

Persistenz ist mit JPA/Hibernate erfolgt.

Manchmal wirft der Webservice eine ungeprüfte Ausnahme. Ich erhalte diese Ausnahme und werfe eine geprüfte Ausnahme aus. Ich möchte nicht, dass die Transaktion zurückgesetzt wird, da die Web-Service-Ausnahme den aktuellen Status ändert. Ich habe die Methode wie folgt kommentiert:

@Transactional(noRollbackFor={XFireRuntimeException.class, Exception.class}) 
public ActionForward callWS(Order order, ....) throws Exception 
    (...) 
    OrderResult orderResult = null; 

    try { 
    orderResult = webService.order(product, user) 
    } catch (XFireRuntimeException xfireRuntimeException) { 
    order.setFailed(true); 
    throw new WebServiceOrderFailed(order); 
    } finally { 
    persist(order); 
    } 
} 

ich immer noch diese Ausnahme erhalten:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly 

Wenn ich versuche, dies zu reproduzieren mit JUnit, wird die Transaktion nicht für Rollback markiert und es ist immer noch möglich um die Transaktion zu begehen.

Wie mache ich Spring die Transaktion nicht rückgängig zu machen?

Antwort

7

Managed einen Testfall für dieses Problem zu schaffen:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations={"file:web/WEB-INF/spring/applicationContext.xml", 
     "file:web/WEB-INF/spring/services.xml"}) 
@Transactional 
public class DoNotRollBackTest { 
    @Autowired FakeService fakeService; 

    @Test 
    @Rollback(false) 
    public void testRunXFireException() { 
     fakeService.doSomeTransactionalStuff(); 
    } 
} 

FakeService:

@Service 
public class FakeService { 
    @Autowired private EcomService ecomService; 
    @Autowired private WebService webService; 

    @Transactional(noRollbackFor={XFireRuntimeException.class}) 
    public void doSomeTransactionalStuff() { 
     Order order = ecomService.findOrderById(459); 

     try { 
      webService.letsThrowAnException(); 
     } catch (XFireRuntimeException e) { 
      System.err.println("Caugh XFireRuntimeException:" + e.getMessage()); 
     } 

     order.setBookingType(BookingType.CAR_BOOKING); 
     ecomService.persist(order); 
    } 
} 

WebService:

@Transactional(readOnly = true) 
public class WebService { 
    public void letsThrowAnException() { 
     throw new XFireRuntimeException("test!"); 
    } 
} 

Dies wird neu die Rollback-Ausnahme.

Dann erkannte ich, dass die Transaktion wahrscheinlich als RollbackOnly in WebService.letsThrowAnException markiert ist, da WebService auch transaktional ist. Ich zog nach Anmerkung:

@Transactional(noRollbackFor={XFireRuntimeException.class}) 
    public void letsThrowAnException() { 

Jetzt wird die Transaktion wird nicht rückgängig gemacht, und ich kann die Änderungen Bestellung verpflichten.

3

Sie dürfen keine Ausnahme auslösen, wenn Spring sie sehen kann. In diesem Fall dürfen Sie nicht WebServiceOrderFailed() werfen. Die Lösung besteht darin, den Code in zwei Methoden aufzuteilen. Die erste Methode führt die Fehlerbehandlung aus und gibt die Ausnahme zurück, die äußere Methode erstellt die Transaktion.

[EDIT] Wie für noRollbackFor: Versuchen Sie Exception.class durch WebServiceOrderFailed.class zu ersetzen.

+1

Dies ist falsch. 'noRollbackFor' überprüft die angegebene Ausnahmeklasse und alle ihre Unterklassen: http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/transaction/annotation/Transactional.html#noRollbackFor() Zusätzlich , standardmäßig aktiviert Ausnahmen den Rollback NICHT: http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html#transaction-declarative-attransactional-settings – ChssPly76

+1

Dies erklärt nicht, warum die Code oben rollt zurück auf 'WebServiceOrderFailed'. –

+0

Meine Vermutung ist, dass WebServiceOrderFailed eine RuntimeException und der obige Code ist ('noRollbackFor = {..., Exception.class} ') kann keinen Effekt haben, da Exception speziell behandelt wird (andernfalls würde der Vererbungscode auch RuntimeException ignorieren, da Exception erweitert wird). –

Verwandte Themen