Using multiple embedded datastores with Spring Boot - spring

I'm trying to set up a Spring Boot application using Spring Data JPA, Neo4J and MongoDB. The goal is to be able to save different entities in each datastore, as well as using cross-store entities.
The project seems to work well with each store individually, but saving a JPA entity raises this exception :
org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
This exception is not raised if I remove all neo4J and mongoDB related code.
Here is a link to the project on github :
GitHub

I managed to get it working by using the configuration of this project.
It looks like I had to add an "transactionManagerRef" attribute to the #EnableJpaRepositories annotation, a bit more configuration for Transition Managers, and modify some dependencies.

Related

Using both GORM & direct JPA/Hibernate datasource in Grails application

We are trying to upgrade our existing Grails application to 5.2.4
We have defined datasource properties in application.yml which gets used during GORM initialization. Rest of the application we use pure JPA/Hibernate (i.e. don't use GORM)
by using datasource defined in a spring style bean.
At high level, issue that we are facing is either GORM or JPA datasource is getting initialized correctly. But both data sources are not getting initialized at the same time.
If I add dependency following dependencies in gradle script,
org.grails.plugins:hibernate5
org.hibernate:hibernate-core:xxx.Final
Then GORM gets initialized correctly. But then we get following issue when doing JPA style queries
Caused by IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: is not mapped [select xxx]
If I remove those dependency, GORM queries fails with following error.
Either class is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
It seems may be some configuration is missing, but nor sure where is the exact issue.
Appreciate any help/suggestions.

jdbc is not able to find data flushed by jpa repository in the same transaction

I have a JUnit 5 testcase which is annotated with #Transactional and it is calling save service (which uses JPA saveandFlush) first, and trying to retrieve the same data/entity by using find service, which is using plain JDBC for searching, but it is not able to find that entity.
When I tried using isolation of the transaction as read_uncommitted it threw exception saying "java.sql.SQLException: READ_COMMITTED and SERIALIZABLE are the only valid transaction levels" please note that I am using Oracle database.
Is there any other way we can read the data which is present in same transaction by JDBC code?
Oracle does not implement Read Uncommited isolation level, so you will not be able to see uncommited changes from other sessions.
As Mark Rotteveel and Marmite Bomber said, two different transactions/connections(JPA and JDBC) can not see each other's uncommitted data, specially for application having Oracle database.
I had to use spring managed jdbc template so that JPA and the JDBC template uses the same transaction and data is visible to each other.

Configuring Spring Boot to use both H2 AND Oracle at the same time

I am writing a Spring Batch job and don't care about restarts and don't want the hassle of creating, securing and managing an Oracle schema for Spring Batch database objects. H2 on the file system is more than enough for us.
The issue is that I am writing an batch job that needs to connect to an Oracle database and failing miserably just trying to get 2 data sources, transaction managers and entity managers. Right now I am trying two H2 database and haven't even tried configuring Oracle database yet.
I have used two Oracle data sources in other Spring Boot applications successfully in the past but this is my first attempt with Spring Batch that has configuration code to create the data source.
I have tried creating two DataSource, EntityManagerFactoryBean and TransactionManager with one using default spring.datasources configuration, default bean names and #Primary.
I have tried creating just a second DataSource, EntityManagerFactoryBean and TransactionManager with different bean names. This seems to have an issue that the TransactionManager orEntityManager is already assigned to the thread.
I have tried creating a dataSource for batch but run into circular bean creation errors.
I have tried creating a BatchConfigurer and that runs into circular bean creation errors.
I have tried creating a JobRepositoryFactoryBean but a default one is still created.
I have tried using a #PersistenceContext on my #Entity classes.
It shouldn't be this hard so I must be missing something. Any help would be appreciated.
Thanks, Wes.
I think I have some success. I am able to eventually run the batch job using Spring Boot 2.2.0 and Spring Batch 4.2.0 but I have to wait for a 5 minute timeout while creating the Entity Manager for H2 for the Spring Batch repository. The Oracle Entity Manager is registered really quickly and before the H2 Entity Manager despite the H2 Entity Manager being #Primary.
I have a separate configuration class for each of my two DataSources. Each one is annotated with #Configuration, #EnableTransactionManagement and #EnableJPARepository.
The one for Spring Batch is using the standard bean names, dataSource, entityManagerFactory and transactionManager. Each #Bean is annotated with #Primary.
One setting that I needed was to add a .packages("org") to the entityManagerFactory bean. This would pick up all of org.springframework including Spring Batch.
The only other real change I have made from common implementations is to set the dialect in the JPA Properties of the Entity Manager.
I needed the spring.main.allow-bean-definition-overriding: true setting.
There may be more to my solution that I should share but I have been at this for a couple of days and have gone in circles. I even remember getting what appeared as a hung process time and and killed the job thinking it was hung. I may have had some "success" early on but just was too quick to kill the execution.
I would still like to know why it is taking so long to create the H2 Entity Manager.
Thanks, Wes.

Adding #EnableBatchProcessing causes TransactionRequiredException errors

I have a Spring Boot 2 application (still in the development stage) running well with JPA, hibernate and so on. The single persistence test I've got right now goes thru fine.
However, when I add #EnableBatchProcessing to the main boot class (the one annotated with #SpringBootApplication) I get the following error during the test phase of the maven build:
javax.persistence.TransactionRequiredException: no transaction is in
progress
If I just remove this annotation the test runs successfully again.
I read somewhere that spring Batch uses a different transaction manager than that used for JPA persistence.
How can I fix this issue?
Thanks in advance.
This is very simple.#EnableBatchProcessing annotation causes Spring Batch to automatically register a transaction manager to use for its transactions, and your JpaTransactionManager never gets used.
Reason:
By default, #EnableBatchProcessing triggers the creation of a DataSourceTransactionManager. This transaction manager knows nothing about JPA/Hibernate which causes the problem you're seeing.
Solution:
Now, if you want to change the transaction manager that Spring Batch uses for transactions, you have to implement the interface BatchConfigurer. There is a link to an example where a user has done this. What he is doing is switching the transaction manager to his own transactionmanager.

Spring JDBCTemplate and Hibernate

I have a Spring, Spring Data, JPA/Hibernate application.
The legacy part of the application uses JdbcTemplate the new stuff uses spring-data/hibernate and everything is wrapped in a transaction.
Problem is when I modify an entity via hibernate and the legacy part of the system attempts to query something that's been modified I don't get the updated values with out having to explicitly "flush" the entity manager each time.
Is it possible execute the JdbcTemplate queries against hibernate's first-level cache?
What about trying this?
Edit: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html
This transaction manager also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access JPA and services which use plain JDBC (without being aware of JPA)! Application code needs to stick to the same simple Connection lookup pattern as with DataSourceTransactionManager (i.e. DataSourceUtils.getConnection(javax.sql.DataSource) or going through a TransactionAwareDataSourceProxy). Note that this requires a vendor-specific JpaDialect to be configured.

Resources