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

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.

Related

What happens when spring transaction isolation level conflicts with database transaction isolation level?

As I know database transaction isolation level is a prior, or spring can override it?
If database level has priority what are the cases to use spring isolation configuration?
There is no such separation as a "database transaction isolation level" and a "spring transaction isolation level".
A DB might implement the isolation levels defined by the SQL standard and a client that starts a transaction might request a specific level of isolation for it.
There are a couple of things to note that however do not present any contradiction:
A DB usually has a default isolation level that is used if a client does not explicitly request a specific level for a transaction. Say, in PostgreSQL the default one is Read Committed and in MySQL it's Repeatable Read.
A DB might not implement all of the isolation levels or have some specifics in their implementation. E.g. Oracle DB does not support the Read Uncommitted and Repeatable Read isolation levels and PostgreSQL's Read Uncommitted mode behaves like Read Committed.
With Spring, when you specify an isolation level either via the #Transactional(isolation = ...) annotation or TransactionTemplate#setIsolationLevel() it makes the JDBC driver issue an SQL command to set the desired level for the current session.
E.g. Oracle JDBC driver will do ALTER SESSION SET ISOLATION_LEVEL = READ COMMITTED for Read Committed.
If an unsupported level is specified it'll throw an exception.
Refs:
https://www.postgresql.org/docs/current/transaction-iso.html
https://docs.oracle.com/cd/E25054_01/server.1111/e25789/consist.htm#CNCPT1312

Mybatis and Spring data with hibernate together

We have a project which is using Spring data with hibernate as ORM.
Now we are introducing new feature for which we want to use Mybatis and eventually replace hibernate with Mybatis in all of the project but in the meanwhile can Mybatis and Hibernate live together for sometime until we make total switch. I am particularly concerned with Mybatis and Hibernate will share connection pool i.e. Hikari CP (default connection pooling that comes with spring boot, yes this project is Spring boot project!). I am not 100% sure that data source will be shared between both of them? So the question is how feasible is to have Mybatis and Hibernate together for some time ?
Honestly I never tested them together - yes both of them on its own plus JDBC, and everything worked properly - but, at first glance, there is no reason why Spring Data JPA with Hibernate and Mybatis cannot share the same connection pool and data source.
First, both frameworks can access and autodetect the same data source and underlying connection pool.
According to your comments, you are probably using Mybatis-Spring-Boot-Starter. This starter will provide you the ability to autodetect the configured data source and register a properly configured SqlSessionFactory with it.
A similar behavior of course is applicable for Spring Data JPA as well.
Moreover neither Mybatis nor Spring Data JPA should impose any restriction - number of connections, etcetera - on the underlying connection pool.
Finally, Spring Data JPA and Mybatis, this last one with the help of the companion library mybatis-spring, both support Spring's annotation-driven transaction management capability, you only need to properly define your #Transactional annotations in your methods.
Despite my recommendation would be, if possible, not to mix in the same service methods your Spring Data repositories and Mybatis mappers, I think there is no reason not to.
Spring Data Hibernate and Mybatis will be able to share the same connection pool, data source, and transaction manager.
However, there are some situations to watch out for, e.g. avoid manipulating the same object loaded by Hibernate with Mybatis.
Account account = AccountRepository.findById( 999 );
account.setAmount(111);
account.setCode(111);
// May use account to read with Mybatis
// But avoid manipulating account with Mybatis
AccountRepository.save( account );
You can get the JDBC connection from a MyBatis session using getConnection() and use it to build an Hibernate session :
sessionFactory.withOptions().connection(connection).openSession();
You can also get a reference to the underlying connection of an Hibernate Session using the doWork method:
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {

Transaction management in database when two spring boot application trying to access the same record

Two spring boot applications are connected to the common database.
I just wanted to know, how to handle the transaction if both the application try to update the record at the same time?
Since you seem to use JPA (via Spring Data JPA) there isn't much to handle.
The database itself will prevent two transactions to update the record at the same time. So one will always be first.
If you use optimistic locking (which is the default with JPA) the second transaction will notice the modified row and rollback.
Without that the second transaction will simply overwrite the changes with it's own changes.

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.

What is the point of using spring transaction while we have database level transaction?

What is the point of using spring transaction while we have database level transaction ?
If you use mysql, oracle or any other db in java, they provide methods to make things inside transaction then why spring transaction if I can do transaction using java DB driver methods ?
It's another layer of abstraction over the database transaction API. So if you wanted to use multiple databases with global transactions, Spring would allow you to do this. While I have never done it, I believe it would allow you to use DB2 and Hibernate together, for example.
Generally, what I've found is, if a feature is available in Spring, it's because there is a use case for it. They don't just put things into the framework without a reason.
Also, Spring provides declarative transaction demarcation, which produces more readable and maintainable Java code. The declarative approach lets us change the transaction strategy easily, without changing the code.
The Declarative transaction management approach allows you to manage the transaction with the help of configuration instead of hard coding in your source code. This means that you can separate transaction management from the business code. You only use annotations or XML based configuration to manage the transactions
We used Spring AOP along with Hibernate using this transaction strategy Here is an example, Spring AOP transaction mangement with Hibernate.

Resources