2009-11-09 99 views
9

方法調用:
1. Struts操作
2.服務類方法(通過@Transactional註解)
3. Xfire的web服務調用如何防止JPA回滾事務?

一切,包括支柱(DelegatingActionProxy)和交易被配置有彈簧。

持久性是使用JPA/Hibernate完成的。

有時web服務會拋出一個未經檢查的異常。我發現這個異常並拋出一個檢查異常。由於Web服務異常更改當前狀態,我不希望事務回滾。我已經註釋這樣的方法:

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

我仍然得到此異常:當我試着使用JUnit來重現此

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

,本次交易未標記爲回滾,它仍然可能進行交易。

如何讓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()。解決方案是將代碼分成兩個方法。第一種方法執行錯誤處理並返回異常,外部方法創建事務。

[編輯]至於noRollbackFor:嘗試用WebServiceOrderFailed.class代替Exception.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-claclarative-attransactional-settings – ChssPly76 2009-11-09 17:08:09

+1

這並不能解釋爲什麼上面的代碼在'WebServiceOrderFailed'上回滾。 – 2009-11-10 07:57:11

+0

我的猜測是WebServiceOrderFailed是一個RuntimeException和上面的代碼('noRollbackFor = {...,Exception。class}')不能有任何效果,因爲Exception是專門處理的(否則,繼承代碼也會忽略RuntimeException,因爲它擴展了Exception)。 – 2009-11-10 08:02:21