对于WebApplicationContext,我应该@Transactional在控制器或服务中添加注解吗?Spring文档让我有些困惑。
@Transactional
这是我的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调度程序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注释的控制器进行调查,而不会对服务进行调查。同时,我看到大量建议,使服务具有交易性而不是控制者。我认为,<context:component-scan base-package="com..." />在上面的spring-servlet.xml 中使用 它,使其包含服务包,这意味着服务是上下文的一部分,因此将“调查”事务性注释。这个准确吗?
<context:component-scan base-package="com..." />
这是让我感到困惑的Spring文档说明:
@EnableTransactionManagement并仅在定义它们的相同应用程序上下文中在bean上查找@Transactional。这意味着,如果将注释驱动的配置放在DispatcherServlet的WebApplicationContext中,则仅检查控制器中的@Transactional bean。你的服务。
此外,如果我将控制器方法定义为事务性的,并且在另一个类中调用事务性方法,是否会对性能产生影响或带来“问题”?根据文档,我的直觉不是,但希望对此进行验证。
不需要@Transactional注释是应在控制器上还是在服务上进行,但通常它将在服务上执行,该服务将对一个应在一个ACID事务中逻辑执行的请求执行逻辑。
在典型的Spring MVC应用程序中,至少需要两个上下文:应用程序上下文和servlet上下文。上下文是一种配置。应用程序上下文保存与整个应用程序相关的配置,而Servlet上下文保存仅与你的servlet相关的配置。这样,servlet上下文是应用程序上下文的子级,并且可以引用应用程序上下文中的任何实体。反之则不成立。
用你的话说
@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注解中声明的包中查找Bean,但仅在@Configuration定义它们的上下文()中进行WebApplicationContext查找。因此,如果你有一个for容器DispatcherServlet(this is a servlet context),则将在你告诉它进行组件扫描的类中@EnableTransactionManagement查找@Transactional该上下文(@Configuration class)。
@EnableTransactionManagement@Transactional
@ComponentScan
@Configuration
WebApplicationContext
DispatcherServlet
@EnableTransactionManagemen
@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上下文的一部分,因此,如果你希望使它们具有事务性,则需要使用来@Configuration为Application Context的类添加注释@EnableTransactionManagement。
Application Context
@EnableTransactionManagement
@Configuration @EnableTransactionManagement @ComponentScan(basePackages = "my.package.services") public class ApplicationContextConfiguration { // now this will scan your my.package.services package for @Transactional }
ContextLoaderListener实例化DispatcherServlet时,将你的Application Context配置与和Servlet Context配置一起使用。(如果你尚未执行完整的基于Java的配置,请参阅javadoc,而不是xml。)
ContextLoaderListener
附录: @EnableTransactionManagement具有与<tx:annotation-driven />Java配置相同的行为。在此处检查是否ContextLoaderListener与XML 一起使用。
<tx:annotation-driven />