如何让@Component class 中的方法成为@Transactional?
How to get a method inside a @Component class to be @Transactional?
我正在编写一个基于 spring-boot 的应用程序。在我的代码中,我有一个管理器 class UManager,其中有一个保存方法。在这个方法中,有两个动作参与其中。第一个使用另一个管理器保存一些数据,第二个使用保存方法保存给定的数据。现在,当两个操作之一可能失败时,都应该撤消。我假设,使用 @Transactional 注释会提供我需要的东西,就好像两个操作之一失败一样,整个事务将被回滚,并且不会向数据库提交任何更改。
@Component
public class UManager {
@Autowired
AManager aManager;
@Autowired
URepository uRepository;
... some stuff happening here
@Transactional
public U save(UBuilder uBuilder) {
aManager.save(something);
uRepository.save(uBuilder.build());
}
}
只要我在save方法中添加@Transactional注解,应用程序就无法启动。我收到以下错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bController': Injection of autowired dependencies failed;
我做错了什么或者我错过了什么?
编辑:
这是堆栈跟踪:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: UManager BController.uManager; nested exception is java.lang.IllegalArgumentException: Can not set UManager field BController.uManager to com.sun.proxy.$Proxy102
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:764) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:357) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:305) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1124) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1113) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at RApplication.main(RApplication.java:44) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_72]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_72]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_72]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_72]
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:467) [spring-boot-maven-plugin-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_72]
编辑 2:
R应用程序:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@SpringBootApplication
@EnableScheduling
@EnableTransactionManagement
public class RApplication {
public static void main(String[] args) {
SpringApplication.run(RaumbuchungApplication.class, args); //this is the line mentioned in the stacktrace
}
}
UManager:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import de.mischok.hfmw.raumbuchung.data.URepository;
import de.mischok.hfmw.raumbuchung.types.U;
import de.mischok.hfmw.raumbuchung.types.UBuilder;
@Component
public class UManager {
@Autowired
URepository uRepository;
@Transactional
public U save(UBuilder uBuilder){
}
}
B控制器:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import UManager;
@Controller
@RequestMapping("my/Path")
public class BController {
@Autowired
UManager uManager;
}
这些是代码的重要部分,因为其他部分不涉及问题。
您必须先创建一个事务管理器,如下所示:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
然后通过指定以下内容使其成为注解驱动:
<tx:annotation-driven transaction-manager = "txManager" />
现在您应该可以使用 @Transactional
。
如果您没有使用 xml spring 配置,但您有一个 Application
class(我猜 RApplication
来自您发布的堆栈跟踪)配置是否确保使用 @EnableTransactionManagement
进行注释
例如:
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableJpaRepositories
@EnableTransactionManagement
public class Application {
//rest code goes here
}
编辑
该错误表明代理对象失败,您应该自动装配要注入的 class (UManager) 的接口,而不是 class 本身。
例如
改变你的 UManager
class 来实现一个接口(当然还要声明 UManager
的任何 public 方法到接口)
public class UManager implements IUManager
并且在您的 bController
class 中自动装配接口而不是 class
public class BController {
@Autowired
IUManager uManager;
}
所描述的错误看起来像是来自另一个尝试 Autowire
UManager 的 bean。我不是 Spring 方面的专家,但是当您输入 Transactional
时,您将其设为 DAO
类型的 Component
,因此您应该将 bean 声明为 Repository
bean 而不是通用的 Component
。 What's the difference between @Component, @Repository & @Service annotations in Spring?.
中有更多关于各种注释之间差异的信息
我正在编写一个基于 spring-boot 的应用程序。在我的代码中,我有一个管理器 class UManager,其中有一个保存方法。在这个方法中,有两个动作参与其中。第一个使用另一个管理器保存一些数据,第二个使用保存方法保存给定的数据。现在,当两个操作之一可能失败时,都应该撤消。我假设,使用 @Transactional 注释会提供我需要的东西,就好像两个操作之一失败一样,整个事务将被回滚,并且不会向数据库提交任何更改。
@Component
public class UManager {
@Autowired
AManager aManager;
@Autowired
URepository uRepository;
... some stuff happening here
@Transactional
public U save(UBuilder uBuilder) {
aManager.save(something);
uRepository.save(uBuilder.build());
}
}
只要我在save方法中添加@Transactional注解,应用程序就无法启动。我收到以下错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bController': Injection of autowired dependencies failed;
我做错了什么或者我错过了什么?
编辑: 这是堆栈跟踪:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: UManager BController.uManager; nested exception is java.lang.IllegalArgumentException: Can not set UManager field BController.uManager to com.sun.proxy.$Proxy102
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:764) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:357) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:305) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1124) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1113) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at RApplication.main(RApplication.java:44) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_72]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_72]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_72]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_72]
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:467) [spring-boot-maven-plugin-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_72]
编辑 2: R应用程序:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@SpringBootApplication
@EnableScheduling
@EnableTransactionManagement
public class RApplication {
public static void main(String[] args) {
SpringApplication.run(RaumbuchungApplication.class, args); //this is the line mentioned in the stacktrace
}
}
UManager:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import de.mischok.hfmw.raumbuchung.data.URepository;
import de.mischok.hfmw.raumbuchung.types.U;
import de.mischok.hfmw.raumbuchung.types.UBuilder;
@Component
public class UManager {
@Autowired
URepository uRepository;
@Transactional
public U save(UBuilder uBuilder){
}
}
B控制器:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import UManager;
@Controller
@RequestMapping("my/Path")
public class BController {
@Autowired
UManager uManager;
}
这些是代码的重要部分,因为其他部分不涉及问题。
您必须先创建一个事务管理器,如下所示:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
然后通过指定以下内容使其成为注解驱动:
<tx:annotation-driven transaction-manager = "txManager" />
现在您应该可以使用 @Transactional
。
如果您没有使用 xml spring 配置,但您有一个 Application
class(我猜 RApplication
来自您发布的堆栈跟踪)配置是否确保使用 @EnableTransactionManagement
例如:
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableJpaRepositories
@EnableTransactionManagement
public class Application {
//rest code goes here
}
编辑 该错误表明代理对象失败,您应该自动装配要注入的 class (UManager) 的接口,而不是 class 本身。
例如
改变你的 UManager
class 来实现一个接口(当然还要声明 UManager
的任何 public 方法到接口)
public class UManager implements IUManager
并且在您的 bController
class 中自动装配接口而不是 class
public class BController {
@Autowired
IUManager uManager;
}
所描述的错误看起来像是来自另一个尝试 Autowire
UManager 的 bean。我不是 Spring 方面的专家,但是当您输入 Transactional
时,您将其设为 DAO
类型的 Component
,因此您应该将 bean 声明为 Repository
bean 而不是通用的 Component
。 What's the difference between @Component, @Repository & @Service annotations in Spring?.