如何让@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 而不是通用的 ComponentWhat's the difference between @Component, @Repository & @Service annotations in Spring?.

中有更多关于各种注释之间差异的信息