2009-11-09 3 views
9

Методы вызова: метод класса
1. Действие Struts
2. Услуги (аннотированный по @Transactional)
3. Xfire WebService вызоваКак предотвратить JPA от отката транзакции?

Все, включая распорки (DelegatingActionProxy) и транзакции выполнен с весной.

Сохранение выполняется с помощью JPA/Hibernate.

Иногда веб-сервис будет вызывать неконтролируемое исключение. Я поймаю это исключение и выдаю проверенное исключение. Я не хочу, чтобы транзакция откатилась, поскольку исключение веб-службы изменяет текущее состояние. Я аннотированный метод, как это:

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

Я все еще получаю это исключение:

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

Когда я пытаюсь воспроизвести это с помощью JUnit, транзакция не помечена для отката, и это все еще возможно для совершения транзакции.

Как заставить Spring не откатывать транзакцию?

ответ

7

Сумел создать тестовый случай для этой проблемы:

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

Это воссоздаст откат-исключение.

Тогда я понял, что транзакция, вероятно, будет отмечена как rollbackOnly в WebService.letsThrowAnException, так как WebService также является транзакционным. Я перешел к аннотации:

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

Теперь транзакция не откатна, и я могу внести изменения в заказ.

3

Вы не должны генерировать исключение, где Spring может его видеть. В этом случае вы не должны бросать WebServiceOrderFailed(). Решение состоит в том, чтобы разбить код на два метода. Первый метод обрабатывает ошибку и возвращает исключение, внешний метод создает транзакцию.

[EDIT] Как для noRollbackFor: Попытайтесь заменить Exception.class на WebServiceOrderFailed.class.

+1

Это неверно. 'noRollbackFor' проверяет указанный класс исключения и все его подклассы: http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/transaction/annotation/Transactional.html#noRollbackFor() Дополнительно , по умолчанию проверенные исключения НЕ будут запускать откат: http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html#transaction-declarative-attransactional-settings – ChssPly76

+1

Это не объясняет, почему выше приведенный выше код возвращается к 'WebServiceOrderFailed'. –

+0

Я предполагаю, что WebServiceOrderFailed - это исключение RuntimeException и код выше ('noRollbackFor = {..., Exception.class} ') не может иметь никакого эффекта, поскольку Exception обрабатывается специально (в противном случае код наследования также игнорирует RuntimeException, поскольку он расширяет Exception). –

Смежные вопросы