Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring Boot@Transactional在@Service类(而不是控制器)上不工作_Spring_Transactions_Spring Boot - Fatal编程技术网

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配置:
您可以尝试以下几点:

  • 执行上述所有配置
  • 从控制器中删除@Transactional配置
  • 将服务对象与事务管理器bean一起引用

  • 更多详情:

    @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,或者。。。。您希望您的服务成为边界,其他一切都是集成。