在@Service类上(而不是控制器上),Spring Boot @Transactional无法正常工作

Jaa*_*tum 5 spring transactions spring-boot

我认为最好的做法是将@Transactional注释放在服务层类上,而不要放在控制器上(请参阅fe 为什么我们不应该将Spring MVC控制器设为@Transactional?)。但这不适用于我的Spring Boot应用程序。这是为什么?

registerAction控制器中的方法(请参见下面的代码)执行多个服务调用。当fe mailService.sendActivationMail(...)失败时,我想从userService.registerUser(...)呼叫中回滚插入的用户。是否需要将@Transactional注释放在控制器类上?

@Transactional在控制器类上设置注释时,我的Spring Boot应用程序正确使用事务:

AuthController.java

@RestController
@RequestMapping("/api/auth")
@Transactional
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private ProfileService profileService;

    @Autowired
    private MailService mailService;

    @RequestMapping(path = "register", method = RequestMethod.POST)
    public Profile registerAction(@Valid @RequestBody Registration registration) {
        ApiUser user = userService.registerUser(registration);
        Profile profile = profileService.createProfile(user, registration);

        mailService.sendActivationMail(user);

        return profile;
    }

}
Run Code Online (Sandbox Code Playgroud)

但是,当在@TransactionalService类上(而不是在控制器上)设置注释时,事务不起作用:

UserService.java

@Service
@Transactional
public class UserService {

    @Autowired
    private ApiUserRepository userRepository;

    public ApiUser registerUser(Registration registration) {
        ...
        userRepository.save(user);
        ...
    }

}
Run Code Online (Sandbox Code Playgroud)

我的配置类:

SpringApiApplication.java

@SpringBootApplication
public class SpringApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringApiCommonApplication.class, args);
    }
}
Run Code Online (Sandbox Code Playgroud)

ApiConfiguration.java

@Configuration
@EnableJpaAuditing
@EnableTransactionManagement
public class ApiConfiguration {
    @Autowired
    private ApiProperties properties;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UsernameCanonicalizer usernameCanonicalizer() {
        return new UsernameCanonicalizer();
    }

    @Bean
    public EmailCanonicalizer emailCanonicalizer() {
        return new EmailCanonicalizer();
    }

    @Bean
    public ApiTokenHandler activationTokenHandler() {
        return new StandardApiTokenHandler(properties.getActivationTokenDuration());
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 -4

您可以将@Transactional注释放在接口定义、接口上的方法、类定义或类上的公共方法之前。然而,仅仅存在注释@Transactional并不足以激活事务行为。

注释@Transactional只是元数据,可以由某些运行时基础设施使用,并且@Transactional-aware可以使用元数据来配置具有事务行为的适当 bean。

在前面的示例中,<tx:annotation-driven/>元素打开事务行为。

    // Below is the service class that we want to make transactional
    @Transactional
    public class DefaultEmployeeService implements EmployeeService {

        void insertEmployee(Employee Employee);

        void updateEmployee(Employee Employee);
    }

    XML Configuration:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" ...>

        <!-- this is the service object that we want to make transactional -->
        <bean id="employeeService" class="service.DefaultEmployeeService"/>

        <!-- enable the configuration of transactional behavior based on annotations -->
        <tx:annotation-driven transaction-manager="txManager"/>

        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- (this dependency is defined somewhere else) -->
            <property name="dataSource" ref="dataSource"/>
        </bean>
    </beans>
Run Code Online (Sandbox Code Playgroud)

您可以尝试的一些要点:

  1. 完成上述所有配置。
  2. 从控制器中删除@Transactional 配置。
  3. 引用 Service 对象以及事务管理器 bean。

更多详细信息:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html