emilly emilly - 13 days ago 4
Java Question

Why transaction here is treated as two separate transactions?

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">

Answer

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.

Comments