Closed
Description
Xiaolong Zuo opened SPR-13843 and commented
I would like to use @Transactional
to private method.I find a way from springdocs 16.5.9,but it's unavailable.
My spring config file like below:
.....
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="tx" mode="aspectj" />
.....
My service class like below:
@Service
public class AdminUsAccountService {
@Autowired
private UsAccountMapper usAccountMapper;
public void out() {
UsAccount usAccount1 = new UsAccount();
usAccount1.setId(1);
usAccount1.setType(1);
usAccountMapper.updateByPrimaryKeySelective(usAccount1);
inner();
}
@Transactional
private void inner() {
UsAccount usAccount2 = new UsAccount();
usAccount2.setId(3);
usAccount2.setType(1);
usAccountMapper.updateByPrimaryKeySelective(usAccount2);
throw new RuntimeException();
}
}
I expect the usAccount1's type is 1 and the usAccount2's type is 0(original value in db is 0),but all the two usAccount's type are 1.
Affects: 4.1.7
Backported to: 4.2.7
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
spring-projects-issues commentedon Jan 6, 2016
Juergen Hoeller commented
How does your account mapper bean work? Have you double-checked that it actually participates in such transactions?
That aside, have you verified that the AspectJ transaction aspect is actually weaved in, either through compile-time weaving or through load-time weaving? Otherwise your
@Transactional
declarations are not going to work at all in that mode, neither on public nor on private methods.You could check
TransactionSynchronizationManager.isActualTransactionActive()
within your inner method to find out whether a transaction has actually been started. Turning on debug logging fororg.springframework.transaction
would also help.Juergen
spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
I find the AspectJ transaction aspect is not actually weaved in, and the method TransactionSynchronizationManager.isActualTransactionActive() return false within all the out and inner method.
In addition,I find the method TransactionSynchronizationManager.isActualTransactionActive() return true when I change the annotation driven mode to proxy.
That's why?
spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
Maybe I lost some configuration?
spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
But I don't find additional configuration in the docs.
spring-projects-issues commentedon Jan 6, 2016
Juergen Hoeller commented
For load-time weaving, you'll need a context:load-time-weaver element in your configuration, and a corresponding class loader underneath (e.g. through specifying the spring-instrument agent using a -javaagent command line argument for your JVM). This is unfortunately a rather advanced configuration arrangement and not as trivial to set up as proxy-based interception.
Let's turn this into a documentation issue. I'll see what we can do for 4.3 there.
Juergen
spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
I'm so sorry, what I just said is not right.
The actual situation is below.
1,When use proxy mode and add
@Transactional
on the out method and the inner method,then the method TransactionSynchronizationManager.isActualTransactionActive() return true.So,all the value of usAccount1 and usAccount2 in db after execute is zero because transaction has been rollback.2,When use aspect mode and add
@Transactional
on the out method and the inner method,then the method TransactionSynchronizationManager.isActualTransactionActive() return false.So,all the value of usAccount1 and usAccount2 in db after execute is one.3,When use aspect mode and only add
@Transactional
on the inner method,then the method TransactionSynchronizationManager.isActualTransactionActive() return false.So,all the value of usAccount1 and usAccount2 in db after execute is one.4,When use proxy mode and only add
@Transactional
on the inner method,then the method TransactionSynchronizationManager.isActualTransactionActive() return false.So,all the value of usAccount1 and usAccount2 in db after execute is one.Now,my code is like this.
The conditions above show that only use proxy mode and add
@Transactional
on the two method can active transaction,but this is not what I want.spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
I think the weave way is CTW usually.
spring-projects-issues commentedon Jan 6, 2016
Juergen Hoeller commented
Compile-time weaving is certainly more reliable. However, it requires special build setup: compiling your application code with
ajc
against the providedspring-aspects
jar.spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
Does CTW need to use AspectJ compiler?
spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
I got it.Thanks very much.I try to use LTW,but get excepetion below.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.weaving.AspectJWeavingEnabler#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:167)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.weaving.LoadTimeWeaverAwareProcessor.postProcessBeforeInitialization(LoadTimeWeaverAwareProcessor.java:97)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 20 more
Caused by: java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
at org.springframework.context.weaving.DefaultContextLoadTimeWeaver.setBeanClassLoader(DefaultContextLoadTimeWeaver.java:91)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1590)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1561)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 29 more
spring-projects-issues commentedon Jan 6, 2016
Xiaolong Zuo commented
The web container what I use is tomcat . When I change weaver-class to TomcatLoadTimeWeaver,then get exception below.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.weaving.AspectJWeavingEnabler#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver]: Constructor threw exception; nested exception is java.lang.IllegalStateException: Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:167)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver]: Constructor threw exception; nested exception is java.lang.IllegalStateException: Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1101)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.weaving.LoadTimeWeaverAwareProcessor.postProcessBeforeInitialization(LoadTimeWeaverAwareProcessor.java:97)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 20 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver]: Constructor threw exception; nested exception is java.lang.IllegalStateException: Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1094)
... 31 more
Caused by: java.lang.IllegalStateException: Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available
at org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver.<init>(TomcatLoadTimeWeaver.java:79)
at org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver.<init>(TomcatLoadTimeWeaver.java:48)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
... 33 more
Caused by: java.lang.NoSuchMethodException: org.apache.catalina.loader.WebappClassLoader.addTransformer(java.lang.instrument.ClassFileTransformer)
at java.lang.Class.getMethod(Class.java:1786)
at org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver.<init>(TomcatLoadTimeWeaver.java:69)
... 39 more
spring-projects-issues commentedon Jan 6, 2016
Juergen Hoeller commented
Which version of Tomcat are you using? Recent versions of Tomcat 7 and 8 should provide that
addTransformer
method out of the box. Alternatively, you could install thespring-instrument-tomcat
jar with its custom subclass of Tomcat's default web app class loader.Juergen
spring-projects-issues commentedon Jan 7, 2016
Xiaolong Zuo commented
Thanks,Juergen.
I have achieved the goal,use the proxy mode with programmatic transaction.
As to why not use aspectJ(CTW),just because the ajc compiler is conflict with lombok.I don't find a way to resolve the problem.
The version of tomcat what I using is tomcat8.I think that the aspectJ(LTW) is a bit complicated,so I give up.