1

我在控制器中自动装配服务。在服务中,我有一个需要抛出异常和数据库更改的场景。所以,我尝试了@Async

@Transactional
public void verifyOtp(OtpDto otpDto)
   ...
   if(xyz){
       deactivateOtp(emp.getId());
       throw new ServException("Mobile no requested is already assigned", "error-code");
   }
}

@Async
@Transactional //with or without
public void deactivateOtp(Integer id){
     otpRepo.deactivateOtp(id);
}

public interface OtpRepository extends JpaRepository<Otp, Integer> {
    @Modifying
    @Query("UPDATE Otp SET isActive = 0 WHERE id = :id")
public void deactiveOtp(@Param("id") Integer id);

这不是创建新线程。但是,如果我在回购中给出,它会起作用

public void deactivateOtp(Integer id){
     otpRepo.deactivateOtp(id);
}

public interface OtpRepository extends JpaRepository<Otp, Integer> {
    @Async
    @Transactional
    @Modifying
    @Query("UPDATE Otp SET isActive = 0 WHERE id = :id")
public void deactiveOtp(@Param("id") Integer id);
4

2 回答 2

1

这被讨论了很多次。

基本上,Spring AOP 不会拦截本地方法调用(在您的情况下deactivateOtp(),在同一个类中调用)

您可以在此处阅读有关此行为的更多信息:了解 AOP 代理

强调:

这里要理解的关键是 Main 类的 main(..) 中的客户端代码具有对代理的引用。这意味着对该对象引用的方法调用将是对代理的调用,因此代理将能够委托给与该特定方法调用相关的所有拦截器(建议)。但是,一旦调用最终到达目标对象,在这种情况下是 SimplePojo 引用,它可能对自身进行的任何方法调用,例如 this.bar() 或 this.foo(),都将针对这个参考,而不是代理。这具有重要意义。这意味着自调用不会导致与方法调用相关的建议有机会执行。

于 2019-12-10T10:19:16.610 回答
1

首先检查服务是否包装到代理中(您可以在控制器中放置一个断点并查看对服务的引用,它将使用代理)。否则配置有问题,@Transactional/@Async直到你修复它才能工作。

现在,假设这不是问题,代码中存在问题:

当控制器调用service.verifyOtp它时,它会转到代理(处理事务),然后转到您的实现。

但是当它到达你的实现并且你调用属于同一个 impl 的方法时,它不会再次通过代理,而是直接进入,deactivateOtp就好像这里根本没有弹簧一样。当然,@Async行不通。

在分辨率方面:

  1. 如果您使用 spring 4.3+,请考虑使用自注入。阅读此线程以获取更多信息。

  2. 或者,重构您的代码,使其deactivateOtp成为另一个类的公共方法。在这种情况下,调用将不再是“内部”的,它将通过代理路径,因此@Async将起作用。

于 2019-12-10T10:42:54.227 回答