2009-11-09 11 views
9

Metody wywoływane:
1. Struts Action
2. Służba metody klasy (odnotowany przez @Transactional)
3. Xfire połączenia webservicesJak uniemożliwić WZP wycofanie transakcji?

Wszystko w tym rozpórki (DelegatingActionProxy) oraz transakcji jest skonfigurowany z wiosny.

Trwałość jest wykonywana za pomocą JPA/Hibernate.

Czasami usługa sieciowa generuje niesprawdzony wyjątek. Przechwycę ten wyjątek i wyrzucę sprawdzony wyjątek. Nie chcę, aby transakcja została wycofana, ponieważ wyjątek usługi sieci Web zmienia bieżący stan. Mam adnotacją metodę tak:

@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); 
    } 
} 

wciąż otrzymuję ten wyjątek:

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

Kiedy próbuję odtworzyć ten z JUnit, transakcja nie jest oznaczony na rolce powraca i jest to nadal możliwe zatwierdzić transakcję.

Jak sprawić, aby Spring nie wycofywał transakcji?

Odpowiedz

7

udało się stworzyć sprawdzian tego problemu:

@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!"); 
    } 
} 

Będzie odtworzyć wycofywania wyjątku.

Następnie zdałem sobie sprawę, że transakcja prawdopodobnie jest oznaczona jako rollback Tylko w WebService.letsThrowAnException ponieważ WebService jest również transakcyjna. Przejdę do adnotacji:

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

Teraz transakcja nie jest wycofywana i mogę zatwierdzić zmiany w Zamówieniu.

3

Nie wolno rzucać wyjątku tam, gdzie Spring może to zobaczyć. W takim przypadku nie wolno rzucać WebServiceOrderFailed(). Rozwiązaniem jest podzielenie kodu na dwie metody. Pierwsza metoda obsługuje błąd i zwraca wyjątek, zewnętrzna metoda tworzy transakcję.

[Edycja] Jeśli chodzi o noRollbackFor: Spróbuj zastąpić Exception.class przez WebServiceOrderFailed.class.

+1

To jest nieprawidłowe. 'noRollbackFor' sprawdza określoną klasę wyjątków i wszystkie jej podklasy: http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/transaction/annotation/Transactional.html#noRollbackFor() Dodatkowo Domyślnie zaznaczone wyjątki NIE spowodują cofnięcia: http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html#transaction-declarative-attransactional-settings – ChssPly76

+1

To nie wyjaśnia, dlaczego powyższy kod cofa się na 'WebServiceOrderFailed'. –

+0

Zgaduję, że WebServiceOrderFailed jest RuntimeException i powyższy kod ('noRollbackFor = {..., Exception.klasa} ') nie może mieć żadnego efektu, ponieważ wyjątek jest obsługiwany specjalnie (w przeciwnym razie kod dziedziczenia również zignorowałby wyjątek RuntimeException, ponieważ rozszerza wyjątek). –