2013-04-23 3 views
4

У нас есть проблемы с откатом транзакций Spring, когда откат, похоже, не работает.
В моем методе уровня обслуживания, который аннотируется с помощью @Transactional Я вызываю три разных класса DAOImpl, чтобы вставить 3 записи.
Средняя вставка делает с 4-го стола, чтобы заполнить поле описания, но это не получилось. Я ожидаю, что первая вставка вернется, но похоже, что это не происходит.
Немного Очки:Весенняя транзакция не откат

  1. 'Получить' метод бросками со средой выполнения Exception
  2. Мы используем org.springframework.jdbc.datasource.DataSourceTransactionManager и MySQL datasource, определенный в applicationContext.xml. Фасоль создаются в Beans.xml, который импортируется в ApplicationContext.xml
  3. Нет @Transactional аннотаций в DAO слое
  4. Мы использовали <tx:annotation-driven transaction-manager="transactionManager"/> снова в applicationContext.xml
  5. Мы используем Spring 3.1

UPDATE:

Фрагменты кода ....

Service Class - это нечто похожее на то, что у меня есть .... Я тестировал с и без @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

Можете ли вы показать нам какой-то код и способ вызова метода Сервиса? изнутри службы или извне? или любая попытка поймать, что вы написали сами? –

+0

У вас есть набор для распространения в определении транзакции –

+0

У вас есть ваше соединение в режиме autocommit? – kan

ответ

3

Поведение @Transactional по умолчанию заключается в том, что транзакционное поведение добавляется с прокси-сервером вокруг объекта (CustomerService в вашем примере). Из reference docs (прокрутите вниз):

В режиме прокси (который по умолчанию), только внешний метод звонки, поступающие через прокси-сервер, перехватываются. Это означает, что самоисключение, по сути, метод в целевом объекте, вызывающий другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызываемый метод отмечен @Transactional.

В вашем примере, внешний вызов handlingIncomingOrders() проходит через прокси-сервер и попадает в целевой объект (экземпляр в CustomerService). Однако последующий вызов saveOrderDetails() является обычным вызовом метода внутри целевого объекта, поэтому транзакционное поведение в прокси никогда не вызывается. Однако, если saveOrderDetails() был вызван из другого класса, вы обнаружите, что транзакционное поведение будет работать должным образом.

+0

Спасибо. Это сработало. Хотя, я нахожу это немного неудобным. Как мы можем изменить режим прокси-сервера по умолчанию? – Ish

+0

Я думаю, что ответ «Рассмотрим использование режима AspectJ (см. Атрибут режима в таблице ниже), если вы ожидаете, что самозаряды также будут обернуты транзакциями. В этом случае не будет прокси-сервера в первую очередь вместо этого целевой класс будет сплетаться (т. е. его байтовый код будет изменен), чтобы превратить @Transactional в поведение во время выполнения любого метода. ' – Ish

+0

@Ish Обычно я делаю четкое определение границы транзакции по используя аннотацию '@ Transactional' на уровне класса. Более того, я избегаю или реорганизую любой (общедоступный) метод, который вызывает целевой объект от себя, так что транзакции будут явными. – matsev

1

Решение в вашем случае будет звонить saveOrderDetails(customerOrder); как proxyBean.saveOrderDetails(customerOrder); Где proxybean is the Object on which Вызывается ручкаIncomingOrders`.

Если CustomerService is singleton (Defualt scope), это может быть так же просто, как добавить код ниже в класс Service.(Добавление ссылки в качестве самостоятельной autowired)

//@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. 
Смежные вопросы