Java @两个不同LocalContainerEntityManagerFactoryBean上的PersistenceContext引发TransactionRequiredException
我设置了两个Java @两个不同LocalContainerEntityManagerFactoryBean上的PersistenceContext引发TransactionRequiredException,java,spring-boot,jpa,entitymanager,Java,Spring Boot,Jpa,Entitymanager,我设置了两个LocalContainerEntityManagerFactoryBeans,一个带有@Primary注释,另一个没有注释。这是因为我必须与两个不同的数据库通信,如果我删除@Primary装饰,我会得到一个重复的bean错误。两者的构造方式完全相同,这里有一个供参考: package com.myorg.rest.config.dba; import ... @Configuration @EnableJpaRepositories( basePackages = &q
LocalContainerEntityManagerFactoryBean
s,一个带有@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;
}
}
它们都是在DAO内部注入@PersistenceContext(unitName=“dbunit”)
和@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();
}
然后,我尝试用@Transactional
装饰DAO,并用@Transactional
进一步装饰每个方法。还尝试了使用@PersistenceContext(unitName=“dbunit”,type=PersistenceContextType.TRANSACTION)注入,但所有这些尝试都会导致完全相同的错误
为什么“次要的”@PersistenceContext
没有将事务放入?当将多个事务管理器与@Transactional
一起使用时,您需要声明要显式使用的事务管理器,否则总是选择@Primary
管理器,您的第二实体管理器不可能加入其事务
尝试使用@Transactional(“dbBTransactionManager”)
插入第二个持久性上下文,看看问题是否消失。这正是我需要的,谢谢。但我不明白的是,如果我通过@PersistenceContext(unitName='nnn')注入,为什么不会自动发生这种情况
如果您同时注入这两种情况呢?另外,Spring不理解持久性上下文和事务管理器之间的关系。如果我将两者都注入,我希望有两个事务,不是吗?当然,Spring是在JPA之上运行的,但是,它已经知道如何处理它了,因为在单个数据源和/或@Primary
的情况下,它已经完美地工作了!也许是因为我不懂这里的基本知识,你有什么好的课程建议来解释这些吗?没有,对不起。老实说,我只是通过研究您的问题学会了如何处理多个TransactionManager
s,并最终在Spring文档中找到了答案,我认为如果您使用调试器停止代码,并调用TransactionSynchronizationManager.isActualTransactionActive()
在抛出TransactionRequiredException
之前,它将返回true
。问题是,这是您的代码无法使用的事务。而TransactionRequiredException
来自Hibernate,而不是Spring
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)