2013-09-17 3 views
3

Ну ... Пытался найти в Google и здесь, но не удалось. Вот моя история:@transactional аннотированный класс, завернутый прокси, но транзакция не создана

  • Spring MVC 3.1.1 RELEASE
  • Spring Data JPA 1.1.0 RELEASE
  • Hibernate 3.6.9.Final

Проблема: У меня есть метод сохранения (. ..) с аннотацией @Transactional (распространение = Propagation.REQUIRES_NEW). Но транзакция не создается.

Другие выводы: 1) Когда я комментирую метод @Transactional от другого сервиса, создается транзакция.

21:49:13.397 [DEBUG] (http-8080-2) org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.xen.components.page.PageServiceImpl.findAllOrdered]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 

2) Услуга, где этот метод находится заворачивает с прокси (я видел в отладке) и способ быть вызван из контроллера, поэтому вызов проходит через прокси-сервер.
3) Обе службы в контексте корневого приложения. Выход log.error (контекста):

OrderServiceImpl - Root WebApplicationContext: startup date [Tue Sep 17 21:48:30 FET 2013]; root of context hierarchy 
PageServiceImpl - Root WebApplicationContext: startup date [Tue Sep 17 21:48:30 FET 2013]; root of context hierarchy 

Вот код метода:

@Service 
public class OrderServiceImpl extends CRUDServiceImpl<Order> implements OrderService { 
private static final Logger log = Logger.getLogger(OrderServiceImpl.class); 

@Autowired 
private OrderRepository repo; 

@Autowired 
private OrderItemService orderItemService; 

@Override 
protected CRUDRepository<Order> getRepository() { 
    return repo; 
} 

@Override 
@Transactional(propagation=Propagation.REQUIRES_NEW) 
public Order save(Order entity) { 
    if (entity.getCreationDate() == null) { 
     entity.setCreationDate(new Date()); 
    } 

    if (entity.getId() == null) { 
     increasePopularityForProductsInOrder(entity); 
     // throws NoTransactionException: No transaction aspect-managed TransactionStatus in scope 
     TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 

     decreaseStockNumberForSkusInOrder(entity); 
    } 

    return super.save(entity); 
} 

private void increasePopularityForProductsInOrder(Order order) { 
    List<OrderItem> items = order.getItems(); 

    for (OrderItem item : items) { 
     orderItemService.increasePopularity(item); 
    } 
} 

private void decreaseStockNumberForSkusInOrder(Order order) { 
    List<OrderItem> items = order.getItems(); 

    for (OrderItem item : items) { 
     orderItemService.removeFromStock(item); 
    } 
} 
} 

Этот метод вызывается из того контроллера. Код контроллера прост, только проверка и orderService.save (...) вызов. Вот мой конфиг:

applicationContext.xml

<beans> 

<context:annotation-config /> 
<context:component-scan base-package="com.xen"> 
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/> 
</context:component-scan> 

<bean id="dataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="url" value="${database.url}" /> 
    <property name="driverClassName" value="${database.driverClassName}" /> 
    <property name="username" value="${database.username}" /> 
    <property name="password" value="${database.password}" /> 
</bean> 

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory"/> 
</bean> 

<tx:annotation-driven proxy-target-class="true"/> 

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> 
    <property name="persistenceUnitName" value="persistenceUnit"/> 
    <property name="dataSource" ref="dataSource"/> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
    </property> 
</bean> 

<jpa:repositories base-package="com.xen" /> 

</beans> 

servletContext.xml

<context:annotation-config /> 
<context:component-scan base-package="com.xen" use-default-filters="false"> 
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/> 
</context:component-scan> 

<mvc:annotation-driven /> 

<mvc:resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/> 

<mvc:default-servlet-handler/> 

<mvc:interceptors> 
    <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/> 
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/> 
    <mvc:interceptor> 
     <mvc:mapping path="/**"/> 
     <bean class="com.xen.common.util.PagePopulationInterceptor" /> 
    </mvc:interceptor> 
</mvc:interceptors> 

<bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource" p:basenames="WEB-INF/i18n/application" p:fallbackToSystemLocale="false"/> 

<bean class="org.springframework.ui.context.support.ResourceBundleThemeSource" id="themeSource"/> 

<bean class="org.springframework.web.servlet.theme.CookieThemeResolver" id="themeResolver" p:cookieName="theme" p:defaultThemeName="standard"/> 

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:defaultErrorView="error"> 
    <property name="warnLogCategory" value="stdout" /> 
    <property name="exceptionMappings"> 
     <props> 
      <prop key=".NoSuchRequestHandlingMethodException">404</prop> 
      <prop key=".NotFoundException">404</prop> 
     </props> 
    </property> 
</bean> 

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver"> 
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/> 
    </bean> 

<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer"> 
    <property name="definitions"> 
      <list> 
      <value>/WEB-INF/layouts/layouts.xml</value> 
      <value>/WEB-INF/views/**/views.xml</value> 
      </list> 
    </property> 
    </bean> 

</beans> 

persistance.xml

<persistence> 
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <properties> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> 
     <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database --> 
     <property name="hibernate.hbm2ddl.auto" value="update" /> 
     <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" /> 
     <property name="hibernate.connection.charSet" value="UTF-8" /> 
    </properties> 
</persistence-unit> 
</persistence> 

Обновление: CartController.java

@Controller 
public class CartController { 
    private static final Logger log = Logger.getLogger(CartController.class); 

... 

@RequestMapping(value = "/cart/submit-order", method = RequestMethod.POST) 
    public String submit(@RequestParam String email, @RequestParam long deliveryType, Model uiModel, HttpServletRequest request, RedirectAttributes redirectAttrs) { 
     Order order = CartHelper.getOrderFromRequest(request); 
     uiModel.addAttribute("email", email); 

     // 1. check if address is set 
     if (StringUtil.isEmpty(order.getClientInfo().getFirstName())) { 
      MessageBean.createErrorMessage("cart.enter-address.error").displayMessage(uiModel); 
      populateForm(uiModel, order); 
      return "cart"; 
     } 

     // 2. check if specified deliveryType exist 
     DeliveryType type = null; 
     try { 
      type = deliveryTypeService.findOne(deliveryType); 
     } catch (NotFoundException nfe) { 
      MessageBean.createErrorMessage("cart.invalid-delivery-type.error").displayMessage(uiModel); 
      populateForm(uiModel, order); 
      return "cart"; 
     } 
     order.setDeliveryType(type); 

     // 3. check if email is valid 
     if (!StringUtil.isEmailValid(email)) { 
      MessageBean.createErrorMessage("cart.invalid-email.error").displayMessage(uiModel); 
      populateForm(uiModel, order); 
      return "cart"; 
     } 
     order.getClientInfo().setEmail(email); 

     // 4. check if order is not empty 
     if (order.isEmpty()) { // should not be possible 
      log.warn("Empty order submission registered! " + order); 
      return "cart/empty"; 
     } 

     order = orderService.save(order); 
     CartHelper.updateOrderForRequest(request, order); 

     // 5. send notification to client 
     try { 
      sendNotificationToClient(order, request); 
      redirectAttrs.addFlashAttribute(MessageBean.MESSAGE_BEAN_KEY, MessageBean.createSuccessMessage("cart.order.successfuly.created")); 
     } catch (Exception e) { 
      redirectAttrs.addFlashAttribute(MessageBean.MESSAGE_BEAN_KEY, MessageBean.createErrorMessage("cart.failed.to.send.notification.during.order.saving")); 
     } 

     return "redirect:/orders/success"; 
    } 

... 

} 

Если у вас есть мысли, пожалуйста, разместите его. Я схожу с ума по этому поводу.

+0

Можете ли вы опубликовать код контроллера? –

+0

С EJB некоторые специальные правила применяются, когда аннотация @TransactionAttribute используется с переопределенным методом. Честно говоря, я не знаю, применимо ли это также к Spring, но на всякий случай попробуйте переименовать этот метод. –

+0

drorb, спасибо за ответ. Я добавил только метод контроллера, который вызывает службу, потому что контроллер довольно большой. –

ответ

0

Попробуйте указать свою транзакции кормушки при инициализации аннотаций, поэтому обновить конфигурационный файл, чтобы быть похожими:

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> 

Надеется, что это помогает.

+0

Ean, спасибо, что поставил. Но не работает.'" transactionManager "- значение по умолчанию для этого атрибута. –

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