0

Here I have below method in spring controller

@Override
@Transactional
public Customer updateCustomer(Custom customer) throws Exception {
.....
depatmentService.updateDepartment(department);
..........


}

I have below method in helper class

@Override
@Transactional(readOnly = false)
public Department updateDepartment(Department department) throws Exception {
.....

}

What i am observering is as soon as thread comes out of method updateDepartment, changes under that method getting committed. I am not sure why ? As default propagation is Propagation.REQUIRED which means that Support a current transaction, create a new one if none exists. Then how come transaction for method updateDepartment is separate from method updateCustomer

I am using JPA( hibernate implementation) with spring transaction. Also i don't see explicitly setting behaviour propagation in xml

Relevant section of transaction management from spring configuration

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>


<tx:annotation-driven transaction-manager="txManager" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mappingResources" value="META-INF/custom-mappings.hbm.xml" />
  <property name="packagesToScan" value="com...,   ...Other packages" />
  <property name="jpaVendorAdapter">
    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
         ...........
    </bean>
  </property>
  <property name="jpaProperties">
    <props>
      <prop key="org.hibernate.envers.default_schema">${jdbc.audit.schema}</prop>
      .........
      <prop key="hibernate.session_factory_name">SessionFactory</prop>
    </props>
  </property>
  <property name="jpaPropertyMap">
    <map>
      <entry key="javax.persistence.validation.factory">
        <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
      </entry>
    </map>
  </property>
</bean>

I have configuration file related to controller also

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">

emilly
  • 10,060
  • 33
  • 97
  • 172
  • 2
    Did you check this: http://stackoverflow.com/questions/4171605/understanding-spring-transactions-what-happens-when-a-transactional-method-cal ? – Paweł Głowacz Aug 03 '15 at 10:30
  • pease add the `updateDepartment` body. – Evgeni Dimitrov Aug 03 '15 at 10:50
  • Add `readOnly=false` to updateCustomer. – Joop Eggen Aug 03 '15 at 11:43
  • Could someone mark this question as duplicate? Similar Question : http://stackoverflow.com/questions/2865055/spring-transactional-method-participating-transaction – Amit Bhati Aug 03 '15 at 11:53
  • @JoopEggen `readonly` attribute only specifies whether updation/insertion is allowed or not but i am not getting how both methods are running in separate transactions inspite of default propagation behaviour i.e `Propagation.REQUIRED`. So with `readonly=false` I wont be able to updateany stuff which I need – emilly Aug 03 '15 at 13:48
  • @emily I think I see your problem. – Joop Eggen Aug 03 '15 at 13:50
  • I don't know why this questions marked as duplicate of `http://stackoverflow.com/questions/2865055/spring-transactional-method-participating-transaction` and closed for answers. This question is opposite of that and asks why two methods running in separate transaction. Can administrator please open it for answers ? – emilly Aug 09 '15 at 08:25
  • @emilly how do you determine that the transaction is committed? What is your spring configuration? Are you sure the controller bean is really transactional? If it's in a spring-mvc context, and the transaction manager is in the root context, it won't be. – JB Nizet Aug 09 '15 at 08:47
  • @JBNizet `how do you determine that the transaction is committed? ` as soon as I come out of helper method I see entry goes in my oracle DB.` Are you sure the controller bean is really transactional?` yes I could see `@Transactional` is written above my controller method. `What is your spring configuration?` its a big configuration and will be very verbose to put it here – emilly Aug 09 '15 at 09:54
  • @JBNizet I have put relevant section from spring configuration. How I can confirm `If controller is in a spring-mvc context, and the transaction manager is in the root context ` ? Even if yes, why controller won't be transactional here ? – emilly Aug 09 '15 at 10:13
  • You should try to strip this down to a [mcve]: only one controller, and one helper class so that other could try it. – Serge Ballesta Aug 09 '15 at 13:18
  • @emilly is this toy only spring xml configuration file, or do you have one that is specific to the dispatcher servlet? – JB Nizet Aug 09 '15 at 16:22
  • @JBNizet I believe you are asking if I have any spring configuration file specific to controller also. Yes I have mentioned in my edit – emilly Aug 09 '15 at 16:33
  • 1
    Yes, I meant "Is this the only...". The controllers are handled by a spring context that is a child context of the root context where the transaction management is configured. So transaction management only applies to beans in the root context, and the Transactional annotation on the controller thus has no effect, because the controller is handled by the child context. – JB Nizet Aug 09 '15 at 16:33
  • @JBNizet: I think you've got it, because with `proxy-target-class="true"` it should work if it was in the same context. One more reason to never put `@Transactional` annotations on controllers... – Serge Ballesta Aug 09 '15 at 16:50
  • @JBNizet I almost got it. I think its related to http://stackoverflow.com/questions/7746633/declaring-spring-bean-in-parent-context-vs-child-context. But is there some way then making the controller transactional with services method ? What if I also declare `` in controllers.xml along with services-beans.xml. should it work logically ? – emilly Aug 09 '15 at 17:04
  • @SergeBallesta I think `proxy-target-class="true"` does not have any impact on controller bean and does not create proxy class for controllers as when I inspect the class in dispatcherservlet I don't see cglib proxy but concrete class itself . Probably because `proxy-target-class="true"` may be applicable for beans in root context but not on child context – emilly Aug 09 '15 at 17:24
  • Yes that's what JBNizet said: transaction management only applies to beans in the application context where the transaction management is configured. As the controller lies in a child context, the post processing cannot create the AOP proxy, neither JDK not CGLib. – Serge Ballesta Aug 09 '15 at 17:30
  • @SergeBallesta In my recent projects, where all my controllers are actually REST services and the controller/routing logic is in the AngularJS application, I make controllers transactional and don't really have a service layer behind them, which I find redundant. No problem so far. And I use a single context for everything, with Java Config. Much simpler. – JB Nizet Aug 09 '15 at 17:32
  • Then it means no way to make controllers transactional. In fact wherever I spot @transactional at controller level its redundant. Right ? – emilly Aug 09 '15 at 17:37
  • @JBNizet: Nice trick. It would be a Fat Ugly Controller, but there is so little in controller layer that it is still acceptable. But do you use proxy-target class="true" or JDK based AOP ? – Serge Ballesta Aug 09 '15 at 17:37
  • I use CGLib proxies. I also find defining interfaces for everything redundant and useless. It was useful in the days when mock frameworks could only mock interfaces. – JB Nizet Aug 09 '15 at 17:43
  • @JB Nizet After reading your and Serge comments, looks like there is no cleaner way to make controllers transactional. In fact wherever I spot transactional at controller level its redundant. Right ? – emilly Aug 10 '15 at 06:12

1 Answers1

1

It is uncommon to have @Transactional annotations on controller methods. The common usage it to put transaction demarcation at service level.

Transactional controllers are possible but have some caveats. First, Spring transaction management is based on Spring AOP and uses JDK proxies by default. It works fine at service level, because services are injected as interfaces in controller. But controllers are not injected as interfaces, so it will not work and you will have to use class target proxying with CGLib proxies for it works. Having controller implementing interfaces with JDK proxies has been reported to work on some Spring versions and fail on other: see this other post

TL/DR: unless you really cannot put transaction demarcation at service level and not at controller level.

Community
  • 1
  • 1
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • I believe Spring uses JDK proxies if class implements interface but used CGLIb automatically if class does not implement any interface. Is n't it ? So it should not be a problem for controllers too – emilly Aug 09 '15 at 10:04
  • No it is not automatic. You must explictely declare it with `@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )` at class level, and you must have cglib in your classpath. – Serge Ballesta Aug 09 '15 at 10:13
  • But when I inspect my any service I see like `MerService$$EEnhancerByCGLIB`. we are using ``. so looks like it enables the cglib only for all classes. Not sure about controller ? – emilly Aug 09 '15 at 11:04
  • Ok : `` forces usage of CGLib proxies for the whole application. – Serge Ballesta Aug 09 '15 at 11:47
  • So you mean to say that @Transactional should work for controller also as proxy will be created for controllers too `` ? If yes transaction should not be committed when thread come out of service method. Right ? – emilly Aug 09 '15 at 16:20
  • For information when I inspect controller inside `DispatcherServlet` I do see concrete class instead of cglib proxy. May be `` does not work for controllers ? – emilly Aug 09 '15 at 16:22
  • After reading your and JB Nizet comments, looks like there is no cleaner way to make controllers transactional. In fact wherever I spot @transactional at controller level its redundant. Right ? – emilly Aug 09 '15 at 18:05