PDA

View Full Version : Unexpected/inappropriate application of rule based transaction attributes



kwan
Dec 1st, 2006, 07:26 AM
I have two similar beans defined, one bean when invoked will call for :

[org.springframework.transaction.interceptor.RuleBa sedTransactionAttribute] - <Applying rules to determine whether transaction should rollback on null>
2006-12-01 12:28:48,857 DEBUG [org.springframework.transaction.interceptor.RuleBa sedTransactionAttribute] - <Winning rollback rule is: RollbackRule with pattern [Exception]>
2006-12-01 12:28:48,857 DEBUG [org.springframework.transaction.interceptor.Transa ctionInterceptor] - <Invoking rollback for transaction on se.lantmateriet.alp.bus.UnderrattelseService.under ratta due to throwable [null]>
2006-12-01 12:28:48,867 DEBUG [org.springframework.orm.hibernate3.HibernateTransa ctionManager] - <Triggering beforeCompletion synchronization>
2006-12-01 12:28:48,867 DEBUG [org.springframework.orm.hibernate3.HibernateTransa ctionManager] - <Initiating transaction rollback>

and thereby rollback (not being able to start the transaction).
The other bean works fine.

Here is the beandef for:
shared parent defination:
<bean id="abstractService" abstract="true" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="doCommitThru*">PROPAGATION_REQUIRES_NEW,-Exception</prop>
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
the bean that does not work:
<bean id="underrattelseService" parent="abstractService">
<property name="proxyInterfaces">
<value>se.lantmateriet.alp.bus.UnderrattelseService</value>
</property>
<property name="target">
<bean id="underrattelseTarget" class="se.lantmateriet.alp.bus.UnderrattelseServiceImpl" parent="abstractServiceTarget">
<property name="usDao">
<ref bean="usDaoDelegate"/>
</property>
<property name="utskick">
<ref bean="utskickService"/>
</property>
</bean>
</property>
</bean>
the bean that works:
<bean id="godkannPaminnService" parent="abstractService">
<property name="proxyInterfaces">
<value>se.lantmateriet.alp.bus.GodkannPaminnService</value>
</property>
<property name="target">
<bean id="godkannTarget" class="se.lantmateriet.alp.bus.GodkannPaminnServiceImpl" parent="abstractServiceTarget">
<property name="usDao">
<ref bean="usDaoDelegate"/>
</property>
<property name="utskick">
<ref bean="utskickService"/>
</property>
</bean>
</property>
</bean>

codes to run
ClassPathResource res = new ClassPathResource(
"alp-context-local.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
UnderrattelseService urs = (UnderrattelseService) factory.
getBean("underrattelseService");
System.exit(urs.underratta());

similar codes to run the other bean. Note that execution will not even enter method underratta().

The two beans used to work well for a long time, then "suddenly" application of rulebased for transaction invokes and causing rollback!

I have been starring at the beandef.xml for many many minutes ... I didn't check the code changes because the problem arises at entry underratta().
I appreciate any clues or response ! Thanks.

/Kwan

karldmoore
Dec 1st, 2006, 07:37 AM
So your saying when you call the method on one service it works and on the other it causes a rollback? Have you debugged UnderrattelseService to see why it causes the rollback? Something might actually be going wrong in this service.

kwan
Dec 1st, 2006, 07:45 AM
you see the execution will not go into UnderrattelseService, it does a rollback because a rule check was performed. This rule check was not performed for godkannPaminnService (and therefore godkannPaminnService can run and complete).
The two services have almost identical definition in beandef, this puzzles me.
/Kwan

karldmoore
Dec 1st, 2006, 08:23 AM
Can you post a more complete log. Also try actually debugging it and see where it goes wrong.

kwan
Dec 1st, 2006, 08:36 AM
The two attached files are debug logs for the two services.
As you can see that they are almodt identical, except for underrattaelseService a rule check applies just before entry into the class. (do a search on "rule" in these logs).

/Kwan

karldmoore
Dec 1st, 2006, 08:42 AM
Can we see the code and the applicationContext?

kwan
Dec 1st, 2006, 08:47 AM
codes attached. What is application context ?
/Kwan

karldmoore
Dec 1st, 2006, 08:53 AM
The XML configuration file that contains all the bean definitions.

kwan
Dec 1st, 2006, 08:57 AM
of course !

karldmoore
Dec 1st, 2006, 09:02 AM
OK, I'll take a look in a hour or two when I get home.

kwan
Dec 1st, 2006, 09:05 AM
Take your time, it's friday.
And happy första advent (the swede way to wait for christmas ..)
/Kwan

karldmoore
Dec 1st, 2006, 12:12 PM
Your main method references alp-context-local.xml, but the file you posted was alp-beandefs.xml.

After patching in some stubs for the files you forgot to attach, the main method ran fine. I can only suggest that either the real XML file has problems in it or an exception is thrown by something that causes the rollback.

karldmoore
Dec 2nd, 2006, 04:48 AM
Another thing I noticed in your code, just a general thing is there are a huge number of beans like this defined.



<bean id="creditcardService" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="creditcardServiceTarget"/>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="load*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="search*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>


You really don't need to do this everytime, you can use define one bean and resuse it. You said you were using pre Spring 2.0, if you decide to use 2.0 onwards there are even better ways of doing it.



<bean id="transactionBean" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<!-- dont define a target this time, this is done in the child bean -->
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="load*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="search*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>

<bean id="creditcardService" parent="transactionBean">
<property name="target">
<bean id="creditcardServiceImpl" class="com.blah.CreditCardService">
<property name="creditcardDao">
<ref local="creditcardDao"/>
</property>
</bean>
</property>
</bean>


If you need to override the default transaction attributes you can do that aswell. It justs cuts down on the cruft that you have to write.



<bean id="creditcardService" parent="transactionBean"
<property name="target">
<bean id="creditcardServiceImpl" class="com.blah.CreditCardService">
<property name="creditcardDao">
<ref local="creditcardDao"/>
</property>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_SUPPORTS</prop>
</props>
</property>
</bean>

kwan
Dec 4th, 2006, 01:41 AM
1. the beandef i sent uses parent = .
2. Spring 1.x is used in this case.
3. The two services having exactly the same debug logs, one has rule based on transaction attribute applied i transaction synchronisation while calling class main method. But not the other one.

My problem stays.
/K

karldmoore
Dec 4th, 2006, 02:25 AM
1. the beandef i sent uses parent = .
2. Spring 1.x is used in this case.
3. The two services having exactly the same debug logs, one has rule based on transaction attribute applied i transaction synchronisation while calling class main method. But not the other one.

My problem stays.
/K

1. Lots of the code didn't use parent which is why I raised it.
2. OK
3. OK

As I said previously however, the main method references alp-context-local.xml, but the file you posted was alp-beandefs.xml. Can you send the right xml file.

kwan
Dec 4th, 2006, 02:37 AM
OK, now you have the rest of the application context.
/Kwan

karldmoore
Dec 4th, 2006, 02:49 AM
Hmmmm, those files look pretty much the same as the code I already had. As I said previously the code worked on my machine, but I was using 2.0. I'll trying it later when I get home on 1.2. I really don't understand why it doesn't work though. Could you try it on 2.0?

kwan
Dec 4th, 2006, 02:58 AM
There must be a reason as to why the rule check was applied, there seems to be NO motivation at all.
Debug at spring source level will give us answer, perhaps.
My project is prepared to go spring 2.0, and I believe you, spring 2.0 works as it should.
What causes the rule check to fire ????
/Kwan
ps I am using "manual transaction management" for the strange bean.

kwan
Dec 4th, 2006, 02:59 AM
I meant my project is NOT going Spring 2.0 /Kwan

karldmoore
Dec 4th, 2006, 03:01 AM
There must be a reason as to why the rule check was applied, there seems to be NO motivation at all.
Debug at spring source level will give us answer, perhaps.
My project is prepared to go spring 2.0, and I believe you, spring 2.0 works as it should.
What causes the rule check to fire ????
/Kwan
ps I am using "manual transaction management" for the strange bean.

Well thats exactly what I did, I debugged it and it worked fine. I suggest you do the same with 1.2. The only reason I can see for why it would rollback that early is that an exception occurs when it enters the proxy. This must be something to do with the transaction, e.g. getting a db connection and creating the transaction.

kwan
Dec 4th, 2006, 03:18 AM
will give it a try !

kwan
Dec 6th, 2006, 03:54 PM
I did a debug and found the bug !

by inserting printStack() , I got:
java.lang.IllegalAccessException: Class org.springframework.aop.support.AopUtils can not access a member of class se.lantmateriet.alp.bus.UnderrattelseService with modifiers "public abstract" at sun.reflect.Reflection.ensureMemberAccess(Reflecti on.java:65) at java.lang.reflect.Method.invoke(Method.java:578) at org.springframework.aop.support.AopUtils.invokeJoi npointUsingReflection(AopUtils.java:335) at org.springframework.aop.framework.ReflectiveMethod Invocation.invokeJoinpoint(ReflectiveMethodInvocat ion.java:181) at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :148) at org.springframework.transaction.interceptor.Transa ctionInterceptor.invoke(TransactionInterceptor.jav a:96) at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :170) at org.springframework.aop.framework.JdkDynamicAopPro xy.invoke(JdkDynamicAopProxy.java:176) at se.lantmateriet.alp.bus.$Proxy2.underratta(Unknown Source) at se.lantmateriet.alp.bus.UnderrattelseServiceImpl.m ain(UnderrattelseServiceImpl.java:612)

It was then not too difficult to see that the word "Public" was missing from interface class:
"Interface UnderrattelseService"
I changed it to :
"Public Interface UnderrattelseService"
Then all went well :-)

The question is only why is this a silent exception ?
A silent exception with a purpose ?! or a not so well exception handling routine.

Thanks for all the replies !

/Kwan

karldmoore
Dec 7th, 2006, 02:12 AM
That must be why it worked on my machine, the stubs I created would have been public by default.

If you think there is a problem here and and it was difficult to work out why it wasn't working, you might want to raise a JIRA issue.

kwan
Dec 11th, 2006, 06:17 AM
JIRA: http://opensource.atlassian.com/projects/spring/browse/SPR-2937
created ;-)