java - 两个不同 LocalContainerEntityManagerFactoryBean 上的 @PersistenceContext 抛出 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;
}
}
它们都使用 和 注入到 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)
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)
然后我尝试用 装饰 DAO @Transactional
,并进一步用 装饰每个单独的方法@Transactional
。还尝试使用 注入@PersistenceContext(unitName = "dbAUnit", type = PersistenceContextType.TRANSACTION)
,但所有这些尝试都会导致完全相同的错误。
为什么“二级”@PersistenceContext
不进行交易?
解决方案
当使用多个事务管理器时@Transactional
,您需要明确声明要使用的事务管理器,否则@Primary
管理器总是被选中,并且您的辅助EntityManager
无法加入其事务。
尝试@Transactional("dbBTransactionManager")
在注入第二个持久性上下文的任何地方使用,以查看问题是否消失。
推荐阅读
- javascript - GTM - 如果客户刷新页面,不要触发 HTML 标记
- python - pythin:如何将字符串转换为 json python
- powershell - 从文件夹中删除特殊的 NTFS 权限
- java - Talend 大数据作业未提交到 Azure HD Insight 集群
- azure - Azure AD B2C 性能
- javascript - 如何在服务器端使用 Jest/Enzyme 测试 ag-grid
- javascript - 将 GMT 日期字符串转换为 PST 日期字符串并将输出格式设置为 'mm/dd/yyyy - hh:mi'
- rust - oxipng throwing RuntimeError: unreachable when called
- angular - 从 angular observable ngrx/store 获取对象
- angular - Angular 存储在 RxJS 的时间间隔内重新获取数据