有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java@transactional注释类使用代理包装,但未创建事务

嗯。。。试图在谷歌和这里找到,但失败了。以下是我的故事:

  • Spring MVC 3.1.1版本
  • Spring Data JPA 1.1.0版本
  • 冬眠3.6.9。决赛

问题:我有方法保存(…)带有@Transactional(propagation=propagation.REQUIRES_NEW)注释。但交易并没有被创建

其他调查结果: 1) 当我用来自其他服务的@Transactional method注释时,事务正在被创建

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) 这两个服务都位于根应用程序上下文中。日志的输出。错误(上下文):

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。保存(…)呼叫 这是我的配置:

应用程序上下文。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>

坚持。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。爪哇

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

...

}

如果你有任何想法,请发出来。我快疯了


共 (1) 个答案

  1. # 1 楼答案

    初始化注释时,请尝试指定事务管理器,以便更新配置文件,如下所示:

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

    希望这有帮助