2009-11-09 7 views
9

Méthodes invoquaient:
1. Struts action
2. méthode de classe de service (annoté par @Transactional)
3. webservice appel XfireComment empêcher JPA d'annuler une transaction?

tout, y compris des entretoises (DelegatingActionProxy) et des transactions est configuré avec le printemps.

La persistance est effectuée avec JPA/Hibernate.

Parfois, le service Web lève une exception non vérifiée. J'attrape cette exception et lance une exception vérifiée. Je ne souhaite pas que la transaction soit annulée, car l'exception de service Web modifie l'état actuel. J'ai annoté la méthode comme ceci:

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

Je reçois encore cette exception:

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

Lorsque je tente de reproduire cela avec JUnit, la transaction n'est pas marqué pour faire reculer et il est toujours possible pour commettre la transaction.

Comment faire en sorte que Spring ne supprime pas la transaction?

Répondre

7

a réussi à créer un test pour ce problème:

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

Cela va recréer la rollback exception.

Puis j'ai réalisé que la transaction est probablement marquée comme rollbackOnly dans WebService.letsThrowAnException car WebService est également transactionnel. Je suis passé à l'annotation:

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

Maintenant, la transaction n'est pas annulée et je peux valider les modifications à Order.

3

Vous ne devez pas lancer une exception où Spring peut la voir. Dans ce cas, vous ne devez pas lancer WebServiceOrderFailed(). La solution consiste à diviser le code en deux méthodes. La première méthode effectue la gestion des erreurs et renvoie l'exception, la méthode externe crée la transaction.

[EDIT] Comme pour noRollbackFor: Essayez de remplacer Exception.class par WebServiceOrderFailed.class.

+1

Ceci est incorrect. 'noRollbackFor' vérifie la classe d'exception spécifiée et toutes ses sous-classes: http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/transaction/annotation/Transactional.html#noRollbackFor() De plus , par défaut, les exceptions vérifiées ne déclencheront PAS l'annulation: http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html#transaction-declarative-attransactional-settings – ChssPly76

+1

Ceci n'explique pas pourquoi Le code ci-dessus revient sur 'WebServiceOrderFailed'. –

+0

Je suppose que WebServiceOrderFailed est une RuntimeException et le code ci-dessus ('noRollbackFor = {..., Exception.class} ') ne peut avoir aucun effet puisque Exception est gérée spécialement (sinon, le code d'héritage ignorerait aussi RuntimeException car il étend Exception). –

Questions connexes