首页 > 解决方案 > Spring TransactionManager 行为与 Spring Data 和 JpaRepository

问题描述

我有一个控制器,它执行以下操作

  1. 一个提交端点,它在数据库中保存一个条目,然后异步调用一些外部服务
  2. 通过观察db来跟踪异步调用的更新(这个调用更新一个关联的表)并更新在第一步中创建的条目的状态

我正在使用@Query Annotation 来验证 db 中是否存在第一步条目,并且它总是返回空。我尝试将其更改为默认的 spring 方法并开始返回插入的值。

我阅读了有关代理、@Transactional 以及 JPARepository 中的非 CRUD 方法如何是非事务性的,并尝试了一些事情,例如事务传播和自我注入,甚至明确标记了 repo 方法 @Transactional。但他们都没有解决这个问题。使用弹簧数据方法解决了它,但我仍然不明白发生了什么。有人可以帮助解释这种行为。

基本代码片段如下

我的控制器

@RestController
public class MyController {

    private final MyService myService;
    private final MyRepository myRepository;


    @Autowired
    public MyController(MyService myService,
                        MyRepository myRepository) {
        this.myService = myService;
        this.myRepository = myRepository;
    }

    @PostMapping(value = "/submit")
    public ResponseEntity<MyResponse> submit(@Valid @RequestBody MyRequest myRequest) {
        return ResponseEntity
                .accepted()
                .body(MyResponse.success(myService.submit(myRequest), "SUBMITTED"));
    }

    /**
     * This method is to update the status of the entry created by /submit endpoint
     * if the asynchoronous process triggered by submit endpoint update an associated table
     */
    @PostConstruct
    private void trackUpdates() {
        ..
        someObserver.subscribe(trackedAssociatedEntity -> {
            myService.trackAndUpdateBasedOnAssociatedEntity(trackedAssociatedEntity);
        });
    }

}

我的服务

@Service
@Transactional
public class MyService {


    private final MyRepository myRepository;


    @Autowired
    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }


     submit(MyRequest myRequest) {
         myRepository.save(myEntity);
         //makes that asynchronous call
    }
    public void trackAndUpdateBasedOnAssociatedEntity(@NotNull MyAssociatedEntity myassociatedEntity) {
        //  This commented call always return empty but the uncommented code works as expected
        //        List<MyEntity> existingEntity =
        //                myRepository.findEntityByField1AndField2(myassociatedEntity.getField1(),myassociatedEntity.getField2());

        List<MyEntity> existingEntities =
                        myRepository.findByField1AndField2(myassociatedEntity.getField1(),myassociatedEntity.getField2());

        if(existingEntities.isEmpty()){
                    //create new
                }else{
                    //update
                }
            }
        }
    }
}

我的存储库

@Repository
public interface MyRepository extends JpaRepository<MyEntity, Long> {

    @Query("SELECT e FROM MyEntity e WHERE e.field1 = ':field1' and e.field2 = ':field2' ")
    List<MyEntity> findEntityByField1AndField2(String field1, String field2);

    List<MyEntity> findByField1AndField2(String field1, String field2);
}

标签: springjpaspring-data-jpatransactionmanager

解决方案


我相信这''是不需要的。请尝试以下方法:

@Repository
public interface MyRepository extends JpaRepository<MyEntity, Long> {

    @Query("SELECT e FROM MyEntity e WHERE e.field1 = :field1 and e.field2 = :field2")
    List<MyEntity> findEntityByField1AndField2(String field1, String field2);

    List<MyEntity> findByField1AndField2(String field1, String field2);
}

推荐阅读