当前,我正在编写Spring Boot应用程序,以将数据从源A中的数据库移动到源B中的另一个数据库。为此,我尝试使用两个数据源配置Spring,并尝试同时从源A检索数据并将其插入源B。我可以从源A检索数据,但是问题是我无法将这些数据插入源B。似乎我没有使用EntityManager正确配置事务。请检查我下面的代码,并帮助我解决这个问题。
这是我的数据源配置类:
@Configuration
@EnableJpaRepositories(
basePackages = ["com.gdce.xgen.repo.psql"],
entityManagerFactoryRef = "psqlEntityManager",
transactionManagerRef = "psqlTransactional")
@EnableTransactionManagement
@ComponentScan("com.gdce.xgen.repo.psql")
class PsqlDataSource {
@Bean("psqlEntityManager")
fun entityManagerFactory(@Qualifier("psqlDataSource1") dataSource: DataSource): LocalContainerEntityManagerFactoryBean {
val em = LocalContainerEntityManagerFactoryBean()
val vendorAdapter: JpaVendorAdapter = HibernateJpaVendorAdapter()
em.dataSource = dataSource
em.jpaVendorAdapter = vendorAdapter
em.setPackagesToScan("com.gdce.xgen.model.psql")
em.setJpaProperties(hibernateProperties())
return em
}
@Bean("psqlDataSource1")
@ConfigurationProperties("psql.datasource.main.configuration")
fun dataSource(@Qualifier("psqlDataSourceProperties") dataSourceProperties: DataSourceProperties): DataSource {
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean("psqlDataSourceProperties")
@ConfigurationProperties("psql.datasource.main")
fun dataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean("psqlTransactional")
fun transactionManager(@Qualifier("psqlEntityManager") entityManager: EntityManager, @Qualifier("psqlDataSource1") dataSource: DataSource): PlatformTransactionManager {
val transactionManager = JpaTransactionManager(entityManager.entityManagerFactory)
transactionManager.dataSource = dataSource
return transactionManager
}
private fun hibernateProperties(): Properties {
val hibernateProperties = Properties()
hibernateProperties.setProperty("hibernate.jdbc.lob.non_contextual_creation", "true")
hibernateProperties.setProperty("hibernate.show_sql", "true")
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update")
hibernateProperties.setProperty("hibernate.jdbc.batch_size", "40000")
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect")
hibernateProperties.setProperty("hibernate.connection.pool_size", "20")
hibernateProperties.setProperty("hibernate.order_inserts", "true")
hibernateProperties.setProperty("hibernate.order_updates", "true")
// hibernateProperties.setProperty("hibernate.format_sql", "true")
return hibernateProperties
}
}
这是我用来将数据插入目标数据源的类
@Service
class InsertRepo {
@Qualifier("psqlEntityManager")
// @Autowired // also tried this but not working and saw many people use @PersistenceContext and tried it too
@PersistenceContext
private lateinit var entityManager: EntityManager
fun migrate(records: ArrayList<Any>) {
records.parallelStream().forEach { record ->
run {
entityManager.persist(record)
}
}
}
}
出现错误输出:
Exception in thread "DefaultDispatcher-worker-1" javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy83.persist(Unknown Source)
at com.gdce.xgen.repo.psql.InsertRepo$migrate$1.accept(InsertRepo.kt:18)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:408)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:16)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
如果我将InsertRepo修改为:
@Service
class InsertRepo {
@Qualifier("psqlEntityManager")
@PersistenceContext
private lateinit var entityManager: EntityManager
@javax.transaction.Transactional
fun migrate(records: ArrayList<Any>) {
records.parallelStream().forEach { record ->
run {
entityManager.persist(record)
}
}
}
}
然后我得到了这个错误日志:
Exception in thread "DefaultDispatcher-worker-1" javax.persistence.TransactionRequiredException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:603)
at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:678)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:737)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:18)
at com.gdce.xgen.repo.psql.InsertRepo$$FastClassBySpringCGLIB$$aa68e733.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.gdce.xgen.repo.psql.InsertRepo$$EnhancerBySpringCGLIB$$85ac330b.migrate(<generated>)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
我也尝试过使用@ org.springframework.transaction.annotation.Transactional,然后收到此错误日志:
Exception in thread "DefaultDispatcher-worker-1" javax.persistence.TransactionRequiredException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:603)
at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:678)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:737)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:17)
at com.gdce.xgen.repo.psql.InsertRepo$$FastClassBySpringCGLIB$$aa68e733.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.gdce.xgen.repo.psql.InsertRepo$$EnhancerBySpringCGLIB$$82673045.migrate(<generated>)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy83.persist(Unknown Source)
at com.gdce.xgen.repo.psql.InsertRepo$migrate$1.accept(InsertRepo.kt:19)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
我试图从entityManager获取事务性,但出现一些错误:
Exception in thread "DefaultDispatcher-worker-1" java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:264)
at com.sun.proxy.$Proxy83.getTransaction(Unknown Source)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:17)
at com.gdce.xgen.repo.psql.InsertRepo$$FastClassBySpringCGLIB$$aa68e733.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.gdce.xgen.repo.psql.InsertRepo$$EnhancerBySpringCGLIB$$3c37a126.migrate(<generated>)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)