2013-04-23 133 views
4

我們有一個Spring事務回滾問題,其中回滾看起來沒有工作。
在我的服務層方法中,用@Transactional註釋,我調用三個不同的DAOImpl類來插入3條記錄。
中間插入從第4個表中獲取填充描述字段,但是失敗。我期望第一次插入回滾,但似乎並沒有發生。
幾點:Spring事務不會回滾

  1. '獲取' 方法拋出運行時異常
  2. 我們使用org.springframework.jdbc.datasource.DataSourceTransactionManagerMySQL datasourceapplicationContext.xml定義。豆類在Beans.xml創建了被導入到ApplicationContext.xml
  3. 沒有@Transactional標註在DAO
  4. 我們在applicationContext.xml
  5. 再次使用<tx:annotation-driven transaction-manager="transactionManager"/>我們使用Spring 3.1

UPDATE

代碼片段....

服務類 - 這與我所擁有的東西類似......我使用和不使用@Autowired進行測試。事務啓用方法在服務類中調用。

 
public class CustomerService { 

    //@Autowired 
    CustomerOrderDAO customerOrderDAOImpl; 
    //@Autowired 
    CustomerItemDAO customerItemDAOImpl; 
    //@Autowired 
    CustomerPromotionDAO customerPromotionDAOImpl; 
    //@Autowired 
    PromotionDAO promotionDAOImpl; 

    //other variables 


    public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) { 
     try { 
      saveOrderDetails(customerOrder); 
      ..... 
      return customerOrder; 
     } catch (Exception e) //TO-DO catch proper exception 
     { 
      //Send error response 
      ....... 
      return customerOrder; 
     } 
    } 

    @Transactional 
    public void saveOrderDetails(CustomerOrder customerOrder) throws Exception { 
      customerOrderDAOImpl.create(customerOrder); 
      .... 
      while (promotionsIterator.hasNext()) { 
       customerPromotion.setPromotionName(promotionDAOImpl.getName(customerOrder.getPromotionId)); 
       customerPromotionDAOImpl.create(customerPromotion); 
      } 
      ...... 
      while (customerItemIterator.hasNext()) { 
       customerItemDAOImpl.create(customerItem); 
      } 

    } 
} 

任何想法? 謝謝。

+3

你能告訴我們一些代碼和調用服務方法的方式嗎?從服務內部還是從外部?或者你自己寫的任何嘗試? – 2013-04-23 10:49:38

+0

您是否在交易定義中設置了傳播 – 2013-04-23 10:57:00

+0

您是否在'autocommit'模式下建立了連接? – kan 2013-04-23 11:39:32

回答

3

@Transactional的默認行爲是事務行爲與對象周圍的代理(在您的示例中爲CustomerService)一起添加。從reference docs(向下滾動):

在代理模式下(這是默認設置),只攔截通過代理進入的外部方法調用。這意味着即使被調用的方法標記爲@Transactional,實際上,自調用目標對象內的方法調用目標對象的另一個方法也不會導致實際的事務處理。

在您的例子,向handlingIncomingOrders()外部呼叫通過代理和擊中​​目標對象(CustomerService的一個實例)。但是,後續對saveOrderDetails()的調用是目標對象內的常規方法調用,因此代理中的事務行爲不會被調用。但是,如果從另一個類中調用saveOrderDetails(),則會發現事務行爲將按預期工作。

+0

謝謝。有效。雖然,我覺得有點不方便。我們如何更改默認代理模式? – Ish 2013-04-26 06:27:06

+0

我認爲答案是'「如果你期望自我調用也被事務包裝,考慮使用AspectJ模式(參見下表中的模式屬性)。在這種情況下,首先不會有代理;相反,目標類將被編織(即其字節代碼將被修改),以便將@Transactional轉變爲任何類型方法的運行時行爲。# – Ish 2013-04-26 06:31:00

+0

@Ish我通常通過以下方式來明確定義我的事務邊界:在類層次上使用'@Transactional'註解,並且避免或重構任何從其自身調用目標對象的(公共)方法,這樣事務將是明確的。 – matsev 2013-04-26 13:16:23

1

您的案例中的解決方案將呼叫saveOrderDetails(customerOrder);作爲proxyBean.saveOrderDetails(customerOrder);其中proxybean is the Object on which handleIncomingOrders`被調用。

如果CustomerServicesingleton(Defualt scope),它可以很簡單,只需將以下代碼添加到Service類。(添加一種自引用作爲自動裝配)

//@Autowired 
CustomerService customerService; // As this is injected its a proxy 

和在該方法中使用它作爲

public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) { 
    try { 
     customerService.saveOrderDetails(customerOrder); 
     ..... 
     return customerOrder; 
    } catch (Exception e) //TO-DO catch proper exception 
    { 
     //Send error response 
     ....... 
     return customerOrder; 
    } 
    } 

如果其範圍是可能的簡單的解決方案Prototype所述一個將是如下。

public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder, CustomerService customerService) { 
    try { 
     customerService.saveOrderDetails(customerOrder); 
     ..... 
     return customerOrder; 
    } catch (Exception e) //TO-DO catch proper exception 
    { 
     //Send error response 
     ....... 
     return customerOrder; 
    } 
    } 

而且您在致電handleIncomingOrders時,請使用以下代碼中建議的更改。

bean.handleIncomingOrders(customerOrder); //Suppose this is old code 
Change it to 
    bean.handleIncomingOrders(customerOrder, bean);// THough it appears as we are sending reference to `THIS` as parameter whcihc can be unnecessary, in case of `Proxy`while inside your method `this` and `Passed reference` will point to different Obejects.