对于web MVC,Spring应用程序是否应在控制器或服务上运行@Transactional?
对于WebApplicationContext,我应该在控制器或服务中放置对于web MVC,Spring应用程序是否应在控制器或服务上运行@Transactional?,spring,service,controller,transactional,Spring,Service,Controller,Transactional,对于WebApplicationContext,我应该在控制器或服务中放置@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:/
@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>
下面是一个服务实现:
@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中使用
,使其包含服务包意味着服务是上下文的一部分,因此将“调查”事务注释。这准确吗
以下是让我感到困惑的Spring文档简介:
@启用TransactionManagement并仅查看
对于同一应用程序上下文中的bean上的@Transactional,它们是
定义于。这意味着,如果将
在DispatcherServlet的WebApplicationContext中的配置
只检查控制器中的@Transactional bean,而不检查控制器中的@Transactional bean
服务
此外,如果我将控制器方法定义为事务性的,并且它在另一个类中调用事务性方法,那么是否存在任何性能影响或“不好”?根据文档,我的直觉是否定的,但我希望验证这一点。该服务是进行事务划分的最佳场所。该服务应该保存用户交互的详细级别用例行为,这意味着在事务中逻辑上可以结合在一起的东西。同样,这样可以在web应用程序粘合代码和业务逻辑之间保持分离 有很多CRUD应用程序没有任何重要的业务逻辑,因为它们有一个只在控制器和数据访问对象之间传递内容的服务层是没有用的。在这些情况下,您可以将事务注释放在数据访问对象上 在控制器上放置事务性注释可能会导致问题,请参阅[Spring MVC文档][1],17.3.2: 使用带注释的控制器类时的常见陷阱 应用需要为其创建代理的功能时发生 控制器对象(例如@Transactional方法)。通常你会 为控制器引入一个接口,以便使用JDK dynamic 代理。要实现这一点,必须移动@RequestMapping 注释,以及任何其他类型和方法级别的注释 (例如@modeldattribute、@InitBinder)到接口以及 映射机制只能“看到”代理公开的接口。 或者,您可以在中激活代理目标class=“true” 应用于控制器的功能配置(在我们的 中的事务场景)。这样做意味着 应该使用基于CGLIB的子类代理,而不是 基于接口的JDK代理。有关各种代理的详细信息,请参见 机制见第9.6节“代理机制” 在属性上设置的事务传播行为决定了当一个事务方法调用另一个事务方法时会发生什么。您可以对其进行配置,以便调用的方法使用相同的事务,或者使其始终使用新事务
通过在示例代码中多次调用您的服务,您正在破坏服务的事务目的。如果将事务性批注放在服务上,则对服务的不同调用将在不同的事务中执行。对于
@transactional
批注应该放在控制器上还是放在服务上没有要求,但通常,它将在一个服务上运行,该服务将为一个请求执行逻辑,该请求在逻辑上应在一个ACID事务中执行
在典型的SpringMVC应用程序中,您至少有两个上下文:应用程序上下文和servlet上下文。上下文是一种配置。应用程序上下文保存与整个应用程序相关的配置,而servlet上下文保存仅与servlet相关的配置。因此,servlet上下文是应用程序上下文的子上下文,可以引用应用程序上下文中的任何实体。事实并非如此
在你的报价中
@启用TransactionManagement并仅在定义它们的相同应用程序上下文中查找bean上的@Transactional。这意味着,如果在DispatcherServlet的WebApplicationContext中放置注释驱动配置,它只检查控制器中的@Transactional bean,而不检查服务
@EnableTransactionManagement
在@ComponentScan
注释中声明的包中查找bean中的@Transactional
,但仅在中定义的上下文(@Configuration
)中查找。因此,如果您的DispatcherServlet
有一个WebApplicationContext
(这是一个servlet上下文),那么@EnableTransactionManagement
将在您告诉它在该上下文中进行组件扫描的类(@Configuration
类)中查找@Transactional
由于您的@服务
类是应用程序上下文的一部分,如果您想使这些类具有事务性,则需要使用@EnableTransactionManagement
为应用程序上下文的@配置
类添加注释
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "my.package.services")
public class ApplicationContextConfiguration {
// now this will scan your my.package.services package for @Transactional
}
在实例化DispatcherServlet时,将应用程序上下文配置与ContextLoaderListener
和Servlet上下文配置一起使用。(对于基于java的完整配置,而不是xml,如果您还没有这样做的话。)
附录:
@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);
}
}
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "my.servlet.package")
public class ServletContextConfiguration {
// this will only find @Transactional annotations on classes in my.servlet.package package
}
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "my.package.services")
public class ApplicationContextConfiguration {
// now this will scan your my.package.services package for @Transactional
}
<beans ...
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
..
</beans>