Spring Boot@Transactional在@Service类(而不是控制器)上不工作
我认为最好将Spring Boot@Transactional在@Service类(而不是控制器)上不工作,spring,transactions,spring-boot,Spring,Transactions,Spring Boot,我认为最好将@Transactional注释放在服务层类上,而不是控制器上(参见f.e.)。但这在我的Spring Boot应用程序上不起作用。为什么呢 控制器中的registerAction方法(参见下面的代码)执行多个服务调用。当f.e.mailService.sendActivationMail(…)失败时,我想从userService.registerUser(…)调用中回滚插入的用户。我是否需要将@Transactional注释放在控制器类上 在控制器类上设置了@Transaction
@Transactional
注释放在服务层类上,而不是控制器上(参见f.e.)。但这在我的Spring Boot应用程序上不起作用。为什么呢
控制器中的registerAction
方法(参见下面的代码)执行多个服务调用。当f.e.mailService.sendActivationMail(…)
失败时,我想从userService.registerUser(…)
调用中回滚插入的用户。我是否需要将@Transactional
注释放在控制器类上
在控制器类上设置了@Transactional
注释时,我的Spring引导应用程序正确使用事务:
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;
}
}
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
@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());
}
}
@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;
}
...
}
@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);
}
...
}
但是,如果在服务类(而不是控制器)上设置了@Transactional
注释,则事务不起作用:
UserService.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;
}
}
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
@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());
}
}
@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;
}
...
}
@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);
}
...
}
我的配置类: SpringApiApplication.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;
}
}
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
@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());
}
}
@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;
}
...
}
@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);
}
...
}
ApiConfiguration.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;
}
}
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
@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());
}
}
@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;
}
...
}
@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);
}
...
}
您可以将
@Transactional
注释放在接口定义、接口上的方法、类定义或类上的公共方法之前。然而,仅仅存在@Transactional
注释并不足以激活事务行为
@Transactional
注释只是一些运行时基础结构可以使用的元数据,这些运行时基础结构是@Transactional-aware
,可以使用元数据配置具有事务行为的适当bean
在前面的示例中,
元素打开事务行为
// 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>
//下面是我们要使其成为事务性的服务类
@交易的
公共类DefaultEmployeeService实现EmployeeService{
无效插入员工(员工);
作废更新员工(员工);
}
XML配置:
您可以尝试以下几点:
更多详情:@M.Deinum让我走上了正确的道路。Spring(boot)不会像其他框架那样自动将控制器调用包装到事务中。因此,您必须向控制器添加
@Transactional
注释,或者将代码从控制器类移动到服务类
将代码从控制器类移动到服务类是更好的做法,因为(除其他外)使代码更易于测试。我就是这么做的
AuthenticationService.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;
}
}
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
@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());
}
}
@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;
}
...
}
@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);
}
...
}
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;
}
}
@Service
@Transactional
public class UserService {
@Autowired
private ApiUserRepository userRepository;
public ApiUser registerUser(Registration registration) {
...
userRepository.save(user);
...
}
}
@SpringBootApplication
public class SpringApiApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApiCommonApplication.class, args);
}
}
@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());
}
}
@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;
}
...
}
@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);
}
...
}
什么不起作用。。。。另外,当使用Spring Boot时,您不需要
@EnableTransactionManagement
Spring Boot已经为您做到了这一点。当我将@Transactional
注释放在服务类(而不是控制器)上时,当控制器中发生运行时异常时,不会回滚。当我将@Transactional
注释放在控制器类上时,会发生回滚。但在控制器上放置@事务性不是最佳实践;那为什么只有当我把它放在控制器上时它才会工作呢?当然不是。。。事务已在该阶段提交,那么为什么要在提交后回滚。。。基本上它是按设计工作的……好吧,但是为什么我读到控制器不应该是事务性的,而服务应该是事务性的,就像这里:因为你不应该。。。事务层就是服务,您的控制器只是一个集成层,应该尽可能薄。如果您想为web服务重用相同的逻辑,您是否要使其成为事务性的?或者JMS,或者。。。。您希望您的服务成为边界,其他一切都是集成。