对于web MVC Spring应用程序应该@Transactional去控制器或服务? [英] For web MVC Spring app should @Transactional go on controller or service?

查看:100
本文介绍了对于web MVC Spring应用程序应该@Transactional去控制器或服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于WebApplicationContext,我应该在控制器或服务中插入 @Transactional 注释吗? Spring文档让我有点困惑。

For WebApplicationContext, should I put @Transactional annotations in the controller or in services? The Spring docs have me a bit confused.

这是我的web.xml:

Here is my web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Alpha v0.02</display-name>
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.json</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

这里是我的application-context.xml定义一个spring dispatcher servlet:

Here is my application-context.xml defining a spring dispatcher servlet:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/beans    
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:annotation-config />
    <mvc:annotation-driven />
    <tx:annotation-driven />

    <context:component-scan base-package="com.visitrend" />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

     <bean id="dataSource"  class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="org.postgresql.Driver" />
        <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/postgres" />
        <property name="user" value="someuser" />
        <property name="password" value="somepasswd" />
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:test.hibernate.cfg.xml" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
      <property name="dataSource" ref="dataSource" />
      <property name="sessionFactory" ref="sessionFactory" />
    </bean>    
</beans>

这里有一个服务接口:

public interface LayerService {
    public void createLayer(Integer layerListID, Layer layer);
}

这是一个服务实现:

@Service
public class LayerServiceImpl implements LayerService {

    @Autowired
    public LayerDAO layerDAO;

    @Transactional
    @Override
    public void createLayer(Integer layerListID, Layer layer) {
        layerDAO.createLayer(layerListID, layer);
    }
}

这里是我的控制器:

@Controller
public class MainController {

    @Autowired
    private LayerService layerService;

    @RequestMapping(value = "/addLayer.json", method = RequestMethod.POST)
    public @ResponseBody
    LayerListSetGroup addLayer(@RequestBody JSONLayerFactory request) {
        layerService.createLayer(request.getListId(), request.buildLayer());
        return layerService.readLayerListSetGroup(llsgID);
    }
}

Spring文档让我有些困惑。似乎表明使用WebApplicationContext意味着只有控制器将调查@Transactional注释,而不是服务。同时我看到吨的建议使服务事务而不是控制器。我想在我们的spring-servlet.xml中使用< context:component-scan base-package =com .../> 包括服务包意味着服务是上下文的一部分,因此将被调查事务注释。这是准确的吗?

The Spring documentation has me a bit confused. It seems to indicate that using a WebApplicationContext means only controllers will be investigated for @Transactional annotations and not services. Meanwhile I see tons of recommendations to make services transactional and not controllers. I'm thinking that using <context:component-scan base-package="com..." /> in our spring-servlet.xml above so that it includes the services packages means the services are part of the context, and therefore will be "investigated" for transactional annotations. Is this accurate?

这里是Spring文档blurb,让我困惑:

Here's the Spring documentation blurb that got me confused:


@EnableTransactionManagement,并且在同一个应用程序上下文中的
定义的bean上只显示
@Transactional。这意味着,如果您在DispatcherServlet的WebApplicationContext中使用注释驱动的
配置, it
只检查控制器中的@Transactional bean,而不是您的
服务。

@EnableTransactionManagement and only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.

如果我将控制器方法定义为事务性的,并且它在另一个类中调用事务方法,那么会有任何性能影响或坏处吗?

Further, is there any performance implications or "badness" if I define a controller method as transactional, and it calls a transactional method in a another class? My hunch is no, based on the documentation, but would love validation on that.

推荐答案

没有要求是否

在一个典型的Spring MVC应用程序中,您将有两个上下文:应用程序上下文和servlet上下文。上下文是一种配置。应用程序上下文保存与整个应用程序相关的配置,而servlet上下文保存与您的servlet相关的配置。因此,servlet上下文是应用程序上下文的子代,并且可以引用应用程序上下文中的任何实体。反之亦然。

In a typical Spring MVC application, you would have, minimally, two contexts: the application context and the servlet context. A context is a sort of configuration. The application context holds the configuration that is relevant for your entire application, whereas the servlet context holds configuration relevant only to your servlets. As such, the servlet context is a child of the application context and can reference any entity in the application context. The reverse is not true.

在您的报价中,


@EnableTransactionManagement只查找@Transactional bean在同一应用程序上下文中定义它们。这意味着,如果将注释驱动配置放在DispatcherServlet的WebApplicationContext中,它仅检查控制器中的@Transactional bean,而不检查您的服务。

@EnableTransactionManagement and only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.

@EnableTransactionManagement @Transactional 包含在 @ComponentScan 注释中声明的包中,但只在它们定义的上下文( @Configuration )中。如果你的 DispatcherServlet 有一个 WebApplicationContext (这是一个servlet上下文),那么 @ EnableTransactionManagement 将在您告诉组件在该上下文中扫描的类中查找 @Transactional @Configuration class)。

@EnableTransactionManagement looks for @Transactional in beans in packages declared in the @ComponentScan annotation but only in the context (@Configuration) they are defined in. So If you have a WebApplicationContext for your DispatcherServlet (this is a servlet context), then @EnableTransactionManagement will look for @Transactional in classes you told it to component scan in that context (@Configuration class).

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "my.servlet.package")
public class ServletContextConfiguration {
    // this will only find @Transactional annotations on classes in my.servlet.package package
}

由于您的 @Service 类是Application上下文的一部分,如果您想事务,那么你需要用 @EnableTransactionManagement 注释你的 @Configuration 类的应用程序上下文。

Since your @Service classes are part of the Application context, if you want to make those transactional, then you need to annotate your @Configuration class for the Application Context with @EnableTransactionManagement.

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "my.package.services")
public class ApplicationContextConfiguration {
    // now this will scan your my.package.services package for @Transactional
}

在实例化DispatcherServlet时,使用您的Application Context配置和 ContextLoaderListener 和您的Servlet Context配置。 (查看javadoc 以获取完整的Java代码)

Use your Application Context configuration with a ContextLoaderListener and your Servlet Context configuration when instantiating your DispatcherServlet. (See the javadoc for a full java based config, instead of xml, if you aren't doing it already.)

附录: @EnableTransactionManagement 在Java配置中具有与< tx:annotation-driven /> 相同的行为。 查看此处以使用 ContextLoaderListener 与XML。

Addendum: @EnableTransactionManagement has the same behavior as <tx:annotation-driven /> in a java configuration. Check here for using ContextLoaderListener with XML.

这篇关于对于web MVC Spring应用程序应该@Transactional去控制器或服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆