Hibernate 过滤器未在异步进程中应用

问题描述 投票:0回答:1

我在我的实体上定义了一个休眠过滤器,我使用方面为所有实现我的 TenantableRepository 的存储库注入该过滤器。

问题是过滤器没有被注入到在 CompletetableFuture 方法中执行的存储库调用中。但过滤器在其外部正确注入。 我知道线程是不同的,但方面两次都被调用。

我希望从所有流中启用过滤器。 API 或异步进程。

这是我定义的用于处理以 find 开头的所有 TenantableRepositories 方法的方面。

@Aspect
@Component
@Slf4j
public class TenantFilterAspect {

    @PersistenceContext
    private EntityManager entityManager;

    @Before("execution(* com.demo.repository.TenantableRepository+.find*(..))")
    public void beforeFindOfTenantableRepository() {
        log.info("Called aspect");
        entityManager
                .unwrap(Session.class)
                .enableFilter(Tenantable.TENANT_FILTER_NAME)
                .setParameter(Tenantable.TENANT_COLUMN, TenantContext.getTenantId());
    }
}

我有一个控制器来测试流量。这里我进行了 2 次存储库调用。一个在主线程,一个在异步

CompletetableFuture
方法下。

import org.springframework.beans.factory.annotation.Autowired;

@RestController
@Slf4j
@RequestMapping(value = "/v1/api/test", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class TestController {

    @Autowired
    MyEntityRepository myEntityRepository;

    @RequestMapping(value = "/aysnc", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE)
    public @ResponseBody
    ResponseEntity<APIResponse> testAsync(HttpServletRequest httpServletRequest) throws InterruptedException {
        Optional<MyEntity> entity = myEntityRepository.findByFirstName("Firstname");
        if(!entity.isEmpty()){
            log.info("1. Main: found entity:{}",entity.get());
        }
        CompletableFuture.runAsync(this::callAsyncMethod);
        return ResponseEntity.status(HttpStatus.OK)
                .body("Ok");
    }

    public void callAsyncMethod() {
        Optional<MyEntity> entity = myEntityRepository.findByFirstName("Firstname");
        if(!entity.isEmpty()){
            log.info("2. Async: found entity:{}",entity.get());
        }
    }

}

问题是过滤器没有被注入到异步

CompletetableFuture
方法
callAsyncMethod()
下的存储库调用中。但过滤器在异步方法之前的第一次存储库调用中被正确注入。 我知道线程是不同的,但方面两次都被调用。我打印了日志,但过滤器仍未启用。

我在这里做错了什么?

spring-boot java-8 aspect hibernate-session hibernate-filters
1个回答
0
投票

Spring Boot 默认启用 Open Entitymanager In View 模式。这意味着在 HTTP 请求的整个持续时间内,有 1 个

EntityManager
可用。该
EntityManager
使用
ThreadLocal
绑定到请求处理线程。

现在执行第一个

findByFirstName
时,它将在此共享
EntityManager
上运行。

您的第二个调用是在不同的线程上完成的,看不到这个共享的实体管理器。因此,方面和存储库都独立运行

EntityManager
共享。

当您将

spring.jpa.open-in-view
属性设置为
false
时,我怀疑第一次调用
findByFirstName
时也会发生同样的情况,因为这会禁用共享
EntityManager

此代码的问题在于,应该从

@Transactional
服务方法内部调用。
@Transactional
将导致在交易期间创建共享
EntityManager


@Service
public MyEntityService {

  private final MyEntityRepository repo;

  public MyEntityService(MyEntityRepository repo) {
    this.repo = repo;
  }
  

  @Transactional
  public Optional<MyEntity> findByFirstname(String firstname) {
    return repo.findByFirstName(firstname);
  }
}

现在,如果您将此服务注入到控制器中(无论如何您都应该这样做),由于

EntityManager
,每个调用都会共享
@Transactional
,它将起作用。

© www.soinside.com 2019 - 2024. All rights reserved.