Spring Boot 2@Transaction批注使自动连接的字段为空字段、为空、Spring、Boot

2023-09-04 02:01:48 作者:阴沟

我正尝试在我的服务的方法中使用@Transactional注释来延迟加载域。但是,在我的实现类上使用@Transactional会使所有自动绑定的字段null

以下是我的实现:

@Service
public class UserServiceImpl implements UserService {

 /**
  * DefaultMapper.
  */
 @Autowired
 private DefaultMapper defaultMapper;

 /**
  * Resource service injection.
  */
 @Autowired
 private ResourceService resourceService;

 /**
  * UserRepository.
  */
 @Autowired
 private UserRepository userRepository;

 /**
  * Jwt Factory.
  */
 @Autowired
 private JwtService jwtService;

 @Override
 @Transactional
 public final UserDto findByLogin(final String login) throws ResourceNotFoundException {
 // user repository is null here when using @Transactional
  User user = this.userRepository.findByLogin(login)
   .orElseThrow(() -> new ResourceNotFoundException(
    resourceService.getMessage(MessageBundle.EXCEPTION, "resource.notfound.user.login")
   ));
  UserDto userDto = defaultMapper.asUserDtoWithRoles(user);
  return userDto;
 }
Spring Boot 中使用 Transactional 注解配置事务管理

提前谢谢您。

推荐答案

事务是使用AOP应用的,Spring中的默认AOP机制是使用代理。使用Spring Boot时,代理模式设置为基于类的代理。

您可以使用以下两种方法中的一种来解决此问题。

从您的方法中删除final 通过将spring.aop.proxy-target-class=false添加到application.properties来禁用基于类的代理 现在,当您加载@Transactional时,这将导致您的UserServiceImpl的代理被创建,准确地说是基于类的代理。发生的情况是为UserServiceImpl创建了一个子类,并且所有方法都被覆盖以应用TransactionInterceptor。但是,由于您的方法被标记为final,所以动态创建的类不能覆盖此方法。因此,该方法查看动态创建的代理类中的字段实例,该实例始终为null

当删除final方法时,可以重写该方法,应用该行为,并且它将查看正确的字段实例(实际UserServiceImpl而不是代理)。

禁用基于类的代理时,您将获得一个JDK动态代理,它基本上是一个实现服务实现的所有接口的瘦包装。它应用添加的行为(事务)并调用实际服务。不需要对实际类进行扩展,因此您可以代理最终方法(只要它是您的接口的一部分)。