无法打开JPA EntityManager进行事务处理;嵌套异常是java.lang.IllegalStateException [英] Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException
问题描述
我对Spring和Spring-Batch尤其新颖。
我仍然设法安装 Spring Batch-Admin 。我添加了自定义作业,并为持久性添加了 Hibernate / JPA 。
一切都按预期工作,直到第一块应该被保留。然后我收到以下错误消息:
org.springframework.transaction.CannotCreateTransactionException:
无法打开JPA EntityManager交易;
嵌套异常是java.lang.IllegalStateException:已经有值
[org.springframework.jdbc.datasource.ConnectionHolder@60d31437]
for key [org.springframework.jdbc.datasource .DriverManagerDataSource @ 12da4b19]
绑定到线程[jobLauncherTaskExecutor-1]
这是 full stacktrace :
org.springframework.transaction.CannotCreateTransactionException:无法打开JPA EntityManager进行事务处理;嵌套异常是java.lang.IllegalStateException:已经值org.springframework.jdbc.datasource.ConnectionHolder@43f9e588用于键[org.springframework.jdbc.datasource.DriverManagerDataSource@84f171a]结合到线程[jobLauncherTaskExecutor-1]
。在在org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:427)
。在组织。 springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
处org.springframework.aop org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
。 framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
在com.sun.proxy。$ Proxy41.saveIfUnique(Unknown Source)
at com.qompa.batch.ArticleItemWriter.write(ArticleItemWriter.java:28)
at org.springframework.batch.core.step .item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:171)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:150)
at org.springframework.batch .core.step.item.FaultTolerantChunkProcessor $ 3.doWithRetry(FaultTolerantChunkProcessor.java:313)
在org.springframework.batch.retry.support.RetryTemplate.doExecute(RetryTemplate.java:240)
。在组织。 springframework.batch.retry.support.RetryTemplate.execute(RetryTemplate.java:187)
在org.springframework.batch.core.step.item.BatchRetryTemplate.execute(BatchRetryTemplate.java:213)
。在org.springframework.batch.core.step.item.FaultTolerantChunkProcessor.write(FaultTolerantChunkProcessor.java:402)
at org.springframework.batch.core.step.item.SimpleChu nkProcessor.process(SimpleChunkProcessor.java:194)
在org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74)
在org.springframework.batch.core。 step.tasklet.TaskletStep $ ChunkTransactionCallback.doInTransaction处org.springframework.batch org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
(TaskletStep.java:386)
。 core.step.tasklet.TaskletStep $ 2.doInChunkContext(TaskletStep.java:264)
在org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
。在组织.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
在org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
。在组织.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
at org.springframewo rk.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
在org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume (SimpleFlow.java:144)
在org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
在org.springframework.batch.core.job .flow.FlowJob.doExecute(FlowJob.java:135)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
at org.springframework.batch.core .launch.support.SimpleJobLauncher $ 1.run(SimpleJobLauncher.java:120)
在java.util.concurrent .ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)$ java.util.concurrent.ThreadPoolExecutor
$ Worker.run(ThreadPoolExecutor.java:615)$ b $在java.lang.Thread.run(Thread.java :724)
引起的:java.lang.IllegalStateException:已经值org.springframework.jdbc.datasource.ConnectionHolder@43f9e588用于键[org.springframework.jdbc.datasource.DriverManagerDataSource@84f171a]结合到线程[ jobLauncherTaskExecutor-1]
。在org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:189)
。在org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:402)
... 36 more
同一个Job在独立应用程序中执行得很好。该问题仅在Spring-Batch-Admin环境中发生。您可以在下面看到项目结构和相关性:
这是覆盖/扩展批处理配置的app-context.xml:
<?xml version =1.0encoding =UTF-8?>
< beans xmlns =http://www.springframework.org/schema/beans
xmlns:xsi =http://www.w3.org/2001/XMLSchema-instancexmlns :batch =http://www.springframework.org/schema/batch
xmlns:context =http://www.springframework.org/schema/context
xmlns:task = http://www.springframework.org/schema/taskxmlns:jdbc =http://www.springframework.org/schema/jdbc
xmlns:tx =http://www.springframework。 org / schema / tx
xsi:schemaLocation =http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org / schema / jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework。 org / schema / beans / spring-beans-3.0.xsd
http://www.springframework.org/schema/context http:// w ww.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-任务3.2.xsd>
< context:component-scan base-package =com.company.batch/>
< context:property-placeholder location =classpath:batch.properties/>
< import resource =classpath:/META-INF/spring/batch/jobs/article-job.xml/>
< bean id =dataSource
class =org.springframework.jdbc.datasource.DriverManagerDataSource>
< property name =driverClassNamevalue =$ {batch.jdbc.driver}/>
< property name =urlvalue =$ {batch.jdbc.url}/>
< property name =usernamevalue =$ {batch.jdbc.user}/>
< property name =passwordvalue =$ {batch.jdbc.password}/>
< / bean>
< bean id =jdbcTemplateclass =org.springframework.jdbc.core.JdbcTemplate>
< property name =dataSourceref =dataSource>< / property>
< / bean>
< bean id =entityManagerFactory
class =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean>
< property name =dataSourceref =dataSource/>
< property name =packagesToScanvalue =com.qompa.batch/>
< property name =jpaVendorAdapter>
< bean class =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter>
< property name =databasevalue =POSTGRESQL>< / property>
< property name =showSqlvalue =true/>
< property name =generateDdlvalue =false/>
< property name =databasePlatformvalue =com.company.utils.persistence.CustomPGDialect/>
< / bean>
< / property>
< property name =jpaProperties>
<道具>
< prop key =hibernate.hbm2ddl.auto>< / prop>
< /道具>
< / property>
< / bean>
< bean id =txManagerclass =org.springframework.orm.jpa.JpaTransactionManager>
< property name =entityManagerFactoryref =entityManagerFactory/>
< / bean>
< tx:annotation-driven transaction-manager =txManager/>
<! - - 计划任务 - >
cron =0 0 * / 4 * * */>
cron =0 15 * / 4 * * */>
< / beans>
到目前为止我所了解的是它与ThreadPoolTaskExecutor 以该 jobLauncherTaskExecutor
bean引用。它似乎处理连接池用于同时运行作业 ...但说实话,我不知道如何更改我的配置以使这些工作正常。
:我甚至不确定它是否是后面提到的ThreadPoolTaskExecutor。但它似乎是实施 TaskExecutor
如果有人遇到类似的问题,或者有建议如何配置我的应用程序,以便可以为我的持久性方法创建事务:请给我一个提示!
错误来自JpaTransactionManager第403行:
TransactionSynchronizationManager.bindResource(getDataSource(),conHolder);
该错误意味着事务管理器试图绑定数据源(不是实体管理器)到线程,但数据源已经在那里,这是意想不到的。注意事务管理器还没有开始将实体管理器绑定到线程,这将发生在JpaTransactionManager第416行:
有两种可能的解释:
-
有人(另一个事务管理器?)将数据源添加到事务管理器之前的线程并且这是意外的。
-
或者没有人向事务管理器添加数据源,只是在任务执行结束时没有人在将其返回到池之前清理线程,可能是由于错误或未处理的异常。
这是否也会发生只有一个执行线程,或者只有当有几个?
为了找出问题所在,这些是一些步骤:
-
使用导致问题的最少数量的线程运行
放入 -
一个在
TransactionSynchronizationMan中的断点ager.bindResource()
查看谁将该连接添加到线程。断点可以是一个条件断点,其条件为线程名称:jobLauncherTaskExecutor-1.equals(Thread.currentThread( ).getName()) -
在
TransactionSynchronizationManager.unbindResource()
中放置一个断点,以查看如果数据源从线程解绑定。当断点出现时,向下滚动堆栈跟踪并查看哪些类正在导致此问题。
I am quite new to Spring and Spring-Batch in particular. Still I somehow managed to install the Spring Batch-Admin. I added custom jobs and Hibernate/JPA for persistence.
Everything is working as expected, up to the point where the first chunk should be persisted. Then I receive the following error-message:
org.springframework.transaction.CannotCreateTransactionException:
Could not open JPA EntityManager for transaction;
nested exception is java.lang.IllegalStateException: Already value
[org.springframework.jdbc.datasource.ConnectionHolder@60d31437]
for key [org.springframework.jdbc.datasource.DriverManagerDataSource@12da4b19]
bound to thread [jobLauncherTaskExecutor-1]
This is the full stacktrace:
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@43f9e588] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@84f171a] bound to thread [jobLauncherTaskExecutor-1]
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:427)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy41.saveIfUnique(Unknown Source)
at com.qompa.batch.ArticleItemWriter.write(ArticleItemWriter.java:28)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:171)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:150)
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor$3.doWithRetry(FaultTolerantChunkProcessor.java:313)
at org.springframework.batch.retry.support.RetryTemplate.doExecute(RetryTemplate.java:240)
at org.springframework.batch.retry.support.RetryTemplate.execute(RetryTemplate.java:187)
at org.springframework.batch.core.step.item.BatchRetryTemplate.execute(BatchRetryTemplate.java:213)
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor.write(FaultTolerantChunkProcessor.java:402)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:194)
at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:386)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@43f9e588] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@84f171a] bound to thread [jobLauncherTaskExecutor-1]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:189)
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:402)
... 36 more
The same Job executes fine in a standalone application. The problem occurs only in the Spring-Batch-Admin environment. Below you can see the project structure and dependencies:
This is the app-context.xml that overrides/extends the Batch-Admin configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<context:component-scan base-package="com.company.batch" />
<context:property-placeholder location="classpath:batch.properties" />
<import resource="classpath:/META-INF/spring/batch/jobs/article-job.xml" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${batch.jdbc.driver}" />
<property name="url" value="${batch.jdbc.url}" />
<property name="username" value="${batch.jdbc.user}" />
<property name="password" value="${batch.jdbc.password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.qompa.batch" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="POSTGRESQL"></property>
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="com.company.utils.persistence.CustomPGDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto"></prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<!-- schedule tasks -->
<task:scheduled-tasks>
<task:scheduled ref="articleRetrieval" method="run"
cron="0 0 */4 * * *" />
<task:scheduled ref="articleConversion" method="run"
cron="0 15 */4 * * *" />
</task:scheduled-tasks>
</beans>
What I understand so far is that it has to do with the ThreadPoolTaskExecutor to which the jobLauncherTaskExecutor
bean refers. It seems to handle connection pooling for concurrently running jobs ... but to be honest I have no clue how to change my configurations to make these things work.
[Edit]: I am not even sure wether it is the afromentioned ThreadPoolTaskExecutor. But it seem s to be an implementation of the TaskExecutor interface.
If anyone ran into a similar issue, or has a suggestion how to configure my application in a way that transactions can be created for my persistence methods: Please give me a hint!
The error comes from JpaTransactionManager line 403:
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
The error means that the transaction manager is trying to bind the datasource (not the entity manager) to the thread, but the datasource is already there and this is unexpected.
Note that the transaction manager had not started yet to bind the Entity Manager to the thread, that would happen next at JpaTransactionManager line 416:
There are two possible explanations:
Somebody (another transaction manager?) is adding the datasource to the thread before the transaction manager and this is unexpected.
Or noone is adding the datasource to the transaction manager, is just that at the end of the task execution noone cleans the thread before returning it to the pool, maybe due an error or an unhandled exception.
One question, does this also happen for only one execution thread, or only when there are several?
To find out what the problem is, these are some steps:
run with a minimal number of threads that cause the problem
put a breakpoint in
TransactionSynchronizationManager.bindResource()
to see who adds the connection to the thread. The breakpoint can be a conditional breakpoint with a condition on the thread name: "jobLauncherTaskExecutor-1".equals(Thread.currentThread().getName())put also a breakpoint in
TransactionSynchronizationManager.unbindResource()
, to see if the datasource is unbound from the thread. when the breakpoints hit, scroll down the stacktrace and see which classes are causing this.
这篇关于无法打开JPA EntityManager进行事务处理;嵌套异常是java.lang.IllegalStateException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!