Announcement Announcement Module
Collapse
No announcement yet.
WebApplicationContext and @Transactional - documentation indicates only controller Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • WebApplicationContext and @Transactional - documentation indicates only controller

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

    Here is my web.xml:

    Code:
    <?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>
    Here is my application-context.xml defining a spring dispatcher servlet:

    Code:
    <?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>
    Here's a service interface:

    Code:
    public interface LayerService {
        public void createLayer(Integer layerListID, Layer layer);
    }
    Here's a service implementation:

    Code:
    @Service
    public class LayerServiceImpl implements LayerService {
    
        @Autowired
        public LayerDAO layerDAO;
    
        @Transactional
        @Override
        public void createLayer(Integer layerListID, Layer layer) {
            layerDAO.createLayer(layerListID, layer);
        }
    }
    And here's my controller:

    Code:
    @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);
        }
    }
    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?

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

    @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. Thanks.

  • #2
    Don't define your controller methods as transactional, unless you want your transaction to depend on the successful rendering/handling of the request. The service-layer is the layer that should coordinate your transactions.

    The documentation is a bit misleading @Transactional will be checked on all beans in the same application context and will not only be bound to @Controllers. However in general for a DispatcherServlets ApplicationContext the statement is true as that should, generally speaking, only contain web-related beans (Controllers, hander mappings etc.).

    Comment

    Working...
    X