Could Not Open JPA EntityManager For Transaction; Nested Exception Is Java.lang.IllegalStateException


Answer :

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.




This normally happens when you have multiple transaction managers in place.


Some hints..


When using annotaion @EnableBatchProcessing, Spring Batch automatically registers a transaction manager , and your JpaTransactionManager may never get used.
If you want to change the transaction manager that spring batch uses, you have to implement the interface BatchConfigurer.(https://blog.codecentric.de/en/2013/06/spring-batch-2-2-javaconfig-part-3-profiles-and-environments/).



You can specify transaction manager for tasklets as follows:



<tasklet transaction-manager="transactionManager">


If you have 2 dataSource, I suggest you to read:



https://github.com/spring-projects/spring-boot/issues/3012



So... configure the main datasource (is important the transaction manager's name)



@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManager",
transactionManagerRef = "transactionManager",
basePackages = "a.b.c")
@PropertySource({"classpath:db_persistence.properties"})
@EnableTransactionManagement


and the other datasource:



@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "another_EntityManager",
transactionManagerRef = "another_transactionManager",
basePackages = "x.y.z")
@PropertySource({"classpath:db_persistence.properties"})
@EnableTransactionManagement


I hope that this help you.



Comments

Popular posts from this blog

Converting A String To Int In Groovy

"Cannot Create Cache Directory /home//.composer/cache/repo/https---packagist.org/, Or Directory Is Not Writable. Proceeding Without Cache"

Android How Can I Convert A String To A Editable