I am a newbie and have been trying for 3 days to get my hands around the type of jdbc transaction support that is available through Spring. Despite all my reading, researching, and testing, I'm still unclear on a few issues I hope you can help me resolve.
I am using Spring JDBC ... JDBCTemplate calls from within a Dao/DaoImpl Spring-Managed Bean. The Dao/DaoImpl Spring-Managed Bean is called from a Service/ServiceImpl Spring-Managed Bean. The Service/ServiceImpl Spring-Managed Bean is called from a Non-Spring Managed object, which uses a BeanFactory to get a reference.
NotManaged
--> ManagedService
--> ManagedDao
I am using Commons Attributes to denote transaction demarkation since we are using JDK 1.4 and I don't want my developers to have to modify the spring-config.xml for every transaction they want (and we don't want to use automatic wiring/name matching/etc.). Here's the configuration:
Code:
<!-- Begin: Transaction Using Jakarta Commons Metadata and AOP to denote Transactions -->
<bean id="metadataAttributes"
class="org.springframework.metadata.commons.CommonsAttributes">
</bean>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
<property name="attributes">
<ref bean="metadataAttributes"/>
</property>
</bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="xuiTransactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource" />
</property>
</bean>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor">
<ref bean="transactionInterceptor"/>
</property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
Through much debugging and reading I discovered the following:
NotManaged
--> ManagedService.transactionalMethod1()
works just fine
NotManaged
--> ManagedService.nonTransactionalMethod()
--> ManagedService.transactionalMethod2()
does NOT provide transaction support due to the fact that the proxy is not being used when a method within a Spring-Managed bean calls another method within a Spring-Managed bean ... even if the endpoint method is marked as transactional. Note that ManagedService.nonTransactionalMethod() iterates over a collection and calls ManagedService.transactionalMethod2() for each object ... and I want to commit or rollback on each object, not on the collection as a whole.
So, I decided that my only (unfortunate) option was to refactor ManagedService.transactionalMethod2() into ManagedServiceHelper.transactionalMethod2(). I setup ManagedServiceHelper as a Spring-Managed Bean in the spring-config.xml, setup ManagedService to have an instance of ManagedServiceHelper provided to it by Dependency Injection, and then do the following:
NotManaged
--> ManagedService.nonTransactionalMethod()
--> ManagedServiceHelper.transactionalMethod2()
To my surprise (and disgust), I am still only getting a Proxy between NotManaged and ManagedService.nonTransactionalMethod(). I am not getting a Proxy (or a transaction) between ManagedService.nonTransactionalMethod() and ManagedServiceHelper.transactionalMethod2().
I do have transactional support working between NotManaged --> ManagedService.transactionalMethod1() so I do not feel that this is a problem with my setup, but I have pasted below some code anyhow.
NotManaged
Code:
managedService = (ManagedService)getSpringContext().getBean("ManagedService", ManagedService.class);
// The call below results in a proper transaction
int result1 = managedService.transactionalMethod1();
// The call below does not have a transaction anywhere in the successive callstack
int result2 = managedService.nonTransactionalMethod1();
ManagedService
Code:
/** Created using Dependency Injection */
ManagedServiceHelper managedServiceHelper=null;
public void setManagedServiceHelper(ManagedServiceHelper msh) {
this.managedServiceHelper = msh;
}
/**
* NOTE: Transaction works properly when called from NotManaged
* @@RuleBasedTransactionAttribute(propagationBehaviorName="PROPAGATION_REQUIRED", isolationLevelName="ISOLATION_READ_COMMITTED")
* @@RollbackRuleAttribute(Throwable.class)
*/
public int transactionalMethod1() {
.
.
.
}
/**
* No Transaction Demarkation
*/
public int nonTransactionalMethod() {
while (iter.hasnext()) {
// I Want Each Call to the next method to be its own transaction
managedServiceHelper.transactionalMethod2(iter.next());
}
.
.
.
}
ManagedServiceHelper
Code:
/**
* NOTE: NO transaction processed by Spring Here when called from ManagedService.nonTransactionalMethod().
* @@RuleBasedTransactionAttribute(propagationBehaviorName="PROPAGATION_REQUIRED", isolationLevelName="ISOLATION_READ_COMMITTED")
* @@RollbackRuleAttribute(Throwable.class)
*/
void transactionalMethod2(Object object) {
.
.
.
}
So, at this point, I need your input on the following:
- Any suggestions on how to accomplish what I'm aiming for above?
- Can someone please spell out clearly where transactions can be proxied and where they cannot?
Thanks in advance.
Erik