无法使用Spring Boot使用Transactional配置EntityManager

时间:2019-10-14 07:30:39

标签: spring multithreading spring-boot jpa spring-data-jpa

当前,我正在编写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)

0 个答案:

没有答案