Spring Boot 中的 PersistenceContext 生命周期

PersistenceContext lifecycle in Spring Boot

我想弄明白 Spring 引导应用程序中的持久性上下文是如何工作的。我使用 Spring Data、Hibernate 和 Hikari。

我无法查明 PersistenceContext 何时创建以及何时关闭。根据几篇文章,例如这篇 https://www.baeldung.com/jpa-hibernate-persistence-context or this one https://dzone.com/articles/how-does-spring-transactional PersistenceContext 生命周期与 EntityManager 生命周期相同。所以我想知道 EntityManager 何时实际创建,更重要的是它何时关闭,最重要的是它是否在事务结束时关闭。根据我的发现,枚举 PersistenceContextType.java 决定了我将拥有什么 PersistenceContextPersistenceContextType.TRANSACTION 应该是默认的,应该导致 SharedEntityManagerInvocationHandler 被用作 EntityManager 的实现并且应该在事务结束时关闭,而 PersistenceContextType.EXTENDED 应该比事务并且应该导致 ExtendedEntityManagerInvocationHandler 正在被使用。所以我试图通过调试来证明它,我发现了以下内容。

  1. PersistenceContextType.EXTENDED 未在任何地方进行评估。 PersistenceAnnotationBeanPostProcessor.java 中有一些用法,但在我的集成测试中断点从未停在那里。

  2. 有时会调用SharedEntityManagerInvocationHandler#invoke,有时会调用ExtendedEntityManagerInvocationHandler#invoke,这并没有告诉我它使用了哪种EntityManager

  3. 在某些场合我什至发现 SharedEntityManagerInvocationHandler 包装 ExtendedEntityManagerInvocationHandler.

问题是 - 如何确定 PersistenceContext 是否在交易结束时关闭?

PersistenceContextType.EXTENDED is not being evaluated anywhere. There is some usage in PersistenceAnnotationBeanPostProcessor.java, but the breakpoint never stopped there in my integration tests.

当您的任何 bean 中有以下字段声明时,您将遇到断点:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

The question is - how is it determined, if the PersistenceContext is closed at the end of transaction or not?

有趣的问题。如果您深入研究 Spring 代码,您会注意到 SharedEntityManagerInvocationHandler 调用了 EntityManagerFactoryUtils.doGetTransactionalEntityManager()。该方法为返回的 EntityManager 实例注册事务同步:

TransactionSynchronizationManager.registerSynchronization(
                                new TransactionalEntityManagerSynchronization(emHolder, emf, transactionData, false));

同步是在事务后关闭 EntityManager 的原因:

protected void releaseResource(EntityManagerHolder resourceHolder, EntityManagerFactory resourceKey) {
            closeEntityManager(resourceHolder.getEntityManager());
        }

您还会注意到 ExtendedEntityManagerInvocationHandler 不会做这样的事情。