英文:
@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() {
// ...
}
@Bean(name = "dbATransactionManager")
@Primary
public PlatformTransactionManager dbATransactionManager() {
// ...
}
Properties additionalProperties() {
// ...
}
}
这两者都在DAO中通过@PersistenceContext(unitName = "dbAUnit")
和@PersistenceContext(unitName = "dbBUnit")
注入,并且它们都成功地启动了相应的EntityManager。我可以在两者中都创建实体,然后检索创建的实体。但当我尝试使用以下代码检索所有实体时:
public List<T> findAll() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> entityQuery = criteriaBuilder.createQuery(clazz);
entityQuery.from(clazz);
return entityManager.createQuery(entityQuery).getResultList();
}
其中一个可以无缺地工作,而另一个则不行(它返回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)
// ...
我随后尝试对DAO进行@Transactional
修饰,并进一步在每个单独的方法上使用@Transactional
修饰。还尝试了使用@PersistenceContext(unitName = "dbAUnit", type = PersistenceContextType.TRANSACTION)
进行注入,但所有这些尝试都导致了完全相同的错误。
为什么“次要”的@PersistenceContext
没有生效事务?
英文:
I have two LocalContainerEntityManagerFactoryBean
s set up, one with @Primary
annotation and one without. This is because I have to communicate with two distinct databases, and if I remove the @Primary
decoration I get a duplicate bean error. Both of them are constructed in the exact same way, here's one for reference:
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;
}
}
Both of them are injected inside DAOs with @PersistenceContext(unitName = "dbAUnit")
and @PersistenceContext(unitName = "dbBUnit")
, and they are both successfully bootstrapping the corresponding EntityManager inside. I can create in both of them and then retrieve the created entity. But when I go to retrieve all entities with the following:
public List<T> findAll() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> entityQuery = criteriaBuilder.createQuery(clazz);
entityQuery.from(clazz);
return entityManager.createQuery(entityQuery).getResultList();
}
One of them works flawlessly and the other one doesn't (it returns 0 entities). After debugging, I've realized that one of them was issuing the insert into...
sql command, while the other one wasn't. I tried to force with entityManager.flush()
and got
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)
I then tried to decorate the DAOs with @Transactional
, and further decorate each individual method with @Transactional
. Also tried injecting with @PersistenceContext(unitName = "dbAUnit", type = PersistenceContextType.TRANSACTION)
, but all of those attempts result in the exact same error.
Why is the 'secondary' @PersistenceContext
not putting the transactions in?
答案1
得分: 1
当在使用多个事务管理器与@Transactional
时,您需要明确声明要使用的事务管理器,否则始终会选择@Primary
管理器,而您的次要EntityManager
可能无法加入其事务。
尝试在注入第二个持久化上下文的地方使用@Transactional("dbBTransactionManager")
,看看问题是否消失。
英文:
When using multiple transaction managers with @Transactional
, you need to declare the transaction manager to use explicitly, otherwise the @Primary
manager always gets selected, and your secondary EntityManager
cannot possibly join its transaction.
Try using @Transactional("dbBTransactionManager")
wherever the second persistence context is injected, to see if the problem goes away.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论