【发布时间】:2016-01-05 15:06:16
【问题描述】:
我认为将@Transactional 注释放在服务层类上而不是控制器上是最佳实践(参见 f.e. Why we shouldn't make a Spring MVC controller @Transactional?)。但这不适用于我的 Spring Boot 应用程序。这是为什么呢?
控制器中的registerAction 方法(参见下面的代码)执行多个服务调用。当 f.e. 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;
}
}
但是当 @Transactional 注解设置在服务类上(而不是控制器上)时,事务不起作用:
UserService.java
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
我的配置类:
SpringApiApplication.java
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
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());
}
}
【问题讨论】:
-
什么不起作用....此外,使用 Spring Boot 时,您不需要
@EnableTransactionManagementSpring Boot 已经为您做到了。 -
当我将
@Transactional注释放在服务类上(而不是在控制器上)时,当控制器中发生 RuntimeException 时不会回滚。当我将@Transactional注释放在控制器类上时,会发生回滚确实。但是将@Transactional放在控制器上并不是最佳做法;那为什么只有放在控制器上才有效呢? -
当然不是...事务在那个阶段已经提交了,为什么要在提交后回滚...基本上它按设计工作...
-
好的,但是为什么我读到控制器不应该是事务性的,但服务应该是这样的:stackoverflow.com/questions/23118789/…
-
因为你不应该......事务层是服务,你的控制器只不过是一个集成层,应该尽可能薄。如果您想为 Web 服务重用相同的逻辑怎么办,您是否要使该逻辑成为事务性的?或者 JMS,或者....您希望您的服务成为其他一切集成的边界。
标签: spring transactions spring-boot