@PersistenceContext 在两个不同的 LocalContainerEntityManagerFactoryBean 上抛出 TransactionRequiredException

@PersistenceContext on two different LocalContainerEntityManagerFactoryBean throws TransactionRequiredException

我设置了两个 LocalContainerEntityManagerFactoryBean,一个有 @Primary 注释,一个没有。这是因为我必须与两个不同的数据库通信,如果我删除 @Primary 装饰,我会得到一个重复的 bean 错误。两者的构造方式完全相同,这里供参考:

package com.myorg.rest.config.dba;

import ...

@Configuration
@EnableJpaRepositories(
    basePackages = "com.myorg.rest.dao.dbA",
    entityManagerFactoryRef = "dbAEntityManager",
    transactionManagerRef = "dbATransactionManager"
    )
@EnableTransactionManagement
public class DbADataSourceConfig {

    @Autowired
    private EnvProperties settings;

    @Bean
    @Primary
    public DataSource prjDataSource() {
        DataSourceProperties ds = settings.getdbADatasource();
        return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
    }

    @Bean(name = "dbAEntityManager")
    @Primary
    public LocalContainerEntityManagerFactoryBean dbAEntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(prjDataSource());
        em.setPackagesToScan(new String[] { "com.myorg.model.entities.dba" });
        em.setPersistenceUnitName("dbAUnit");

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());
        // em.afterPropertiesSet();

        return em;
    }

    @Bean(name = "dbATransactionManager")
    @Primary
    public PlatformTransactionManager dbATransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(dbAEntityManager().getObject());

        return transactionManager;
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        return properties;
    }
}

它们都通过 @PersistenceContext(unitName = "dbAUnit")@PersistenceContext(unitName = "dbBUnit") 注入到 DAO 中,并且它们都成功地在内部引导了相应的 EntityManager。我可以在它们中创建,然后检索创建的实体。但是当我使用以下内容检索所有实体时:

public List<T> findAll() {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> entityQuery = criteriaBuilder.createQuery(clazz);
    entityQuery.from(clazz);
    return entityManager.createQuery(entityQuery).getResultList();
}

其中一个可以完美运行,而另一个则不能(returns 0 个实体)。调试后,我意识到其中一个正在发出 insert into... sql 命令,而另一个则没有。我试图用 entityManager.flush() 强制并得到

 Caused by:
            javax.persistence.TransactionRequiredException: no transaction is in progress
                at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413)
                at org.hibernate.internal.SessionImpl.checkTransactionNeededForUpdateOperation(SessionImpl.java:3398)
                at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1355)
                at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1350)
                at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.base/java.lang.reflect.Method.invoke(Method.java:566)
                at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
                at com.sun.proxy.$Proxy95.flush(Unknown Source)

然后我尝试用 @Transactional 修饰 DAO,并进一步用 @Transactional 修饰每个单独的方法。还尝试使用 @PersistenceContext(unitName = "dbAUnit", type = PersistenceContextType.TRANSACTION) 进行注入,但所有这些尝试都会导致完全相同的错误。

为什么 'secondary' @PersistenceContext 没有放入交易?

@Transactional 中使用多个事务管理器时,您需要显式声明要使用的事务管理器,否则总是会选择 @Primary 管理器,而您的辅助 EntityManager 不可能加入它的交易。

尝试在注入第二个持久性上下文的地方使用@Transactional("dbBTransactionManager"),看看问题是否消失。