gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 04:58:51 27 4
gpt4 key购买 nike

好吧...试图在谷歌和这里找到,但失败了。这是我的故事:

  • Spring MVC 3.1.1发布
  • Spring Data JPA 1.1.0发行版
  • 休眠3.6.9。最终

  • 问题:我有带有@Transactional(propagation = Propagation.REQUIRES_NEW)批注的方法save(...)。但是没有创建交易。

    其他发现:
    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)此方法所在的服务被代理(在调试中看到)包装,并且方法从 Controller 调用,因此调用通过代理进行。
    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);
    }
    }
    }

    此方法是从 Controller 调用的。 Controller 代码很简单,仅需验证和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";
    }

    ...

    }

    如果您有任何想法,请发布。我对此感到疯狂。

    最佳答案

    初始化注解时,请尝试指定事务管理器,以便将配置文件更新为:

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

    希望这可以帮助。

    关于java - @transactional带注释的类,使用代理包装,但未创建事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18858880/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com