我认为最佳做法是将@Transactional
注释放在服务层类而不是控制器上(参见f.e. Why we shouldn't make a Spring MVC controller @Transactional?)。但这不适用于我的Spring Boot应用程序。那是为什么?
控制器中的registerAction
方法(请参阅下面的代码)执行多个服务调用。当f.e。 mailService.sendActivationMail(...)
失败,我想从userService.registerUser(...)
调用回滚插入的用户。我是否需要将@Transactional
注释放在控制器类上?
我的Spring Boot应用程序在控制器类上设置@Transactional
注释时正确使用事务:
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());
}
}
答案 0 :(得分:2)
@ M.Deinum 让我走上正轨。 Spring(引导)不会像其他框架那样自动将控制器调用包装在事务中。因此,您必须向控制器添加@Transactional
注释,或者将代码从控制器类移动到服务类。
将代码从控制器类移动到服务类是更好的事情,因为(除其他外)使代码更易于测试。这就是我所做的。
<强> AuthenticationService.java 强>
@Service
public class AuthenticationService {
@Autowired
private UserManager userManager;
@Autowired
private ProfileManager profileManager;
@Autowired
private MailManager mailManager;
@Transactional
public Profile registerUser(Registration registration) {
ApiUser user = userManager.registerUser(registration);
Profile profile = profileManager.createProfile(user, registration);
mailManager.sendActivationMail(user);
return profile;
}
...
}
<强> AuthController.java 强>
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private AuthenticationService authenticationService;
@RequestMapping(path = "register", method = RequestMethod.POST)
@ApiOperation(value = "Registers a user")
public Profile register(@Valid @RequestBody Registration registration) {
return authenticationService.registerUser(registration);
}
...
}
答案 1 :(得分:-3)
您可以将@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>
您可以尝试一些观点:
更多详情:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html