Spring Transaction Not Rollback

We have problems with Spring transaction rollback, where the rollback does not seem to work.
In my service level method, which is annotated using @Transactional , I call three different DAOImpl classes to insert 3 records.
The middle insert makes a receipt from the 4th table to fill in the description field, but this did not work. I expect the first insert to return, but it doesn't seem to be happening.
A few points:

  • Get method gets runtime exception
  • We use org.springframework.jdbc.datasource.DataSourceTransactionManager and MySQL datasource defined in applicationContext.xml . Beans are created in Beans.xml , which is imported into applicationContext.xml
  • No @Transactional annotations in the DAO layer
  • We again used <tx:annotation-driven transaction-manager="transactionManager"/> in applicationContext.xml
  • We use Spring 3.1

UPDATE

Code snippets ....

Service Class is something similar to what I have .... I tested with and without @Autowired. The transaction resolution method is called inside the service class.

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

     }
 }

Any idea? Thanks.

+4
source share
2 answers

The default behavior of @Transactional is that transactional behavior is added with a proxy server around the object ( CustomerService in your example). From reference documents (scroll down):

In proxy mode (which is the default), only calls to external methods that come through the proxy are intercepted. This means that self-exclusion, essentially a method in the target that calls another method of the target, will not lead to an actual transaction at runtime, even if the called method is marked with @Transactional.

In your example, an external call to handlingIncomingOrders() goes through the proxy server and removes the target (an instance of CustomerService ). However, the subsequent call to saveOrderDetails() is a normal method call inside the target, so transactional behavior in the proxy is never called. However, if saveOrderDetails() was called from another class, you will find that the transactional behavior will work as expected.

+3
source

The solution in your case will call saveOrderDetails(customerOrder); as proxyBean.saveOrderDetails(customerOrder); Where proxybean is the Object on which called proxybean is the Object on which handleIncomingOrders`.

If CustomerService is a singleton (Defualt scope), it can be as simple as adding the code below to the Service class. (adding self-determination as automatically)

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

and in the method use it like

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

If its scope is Prototype , one of the possible simple solutions would be as follows.

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

And where you call handleIncomingOrders use the changes suggested in the lower code.

  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. 
+1
source

All Articles