One other thing I'm finding, is that it appears that Javers is grabbing all of the available Connections out of my connection pool (created via Spring DataSourceBuilder). I'm not using Hibernate/JPA, just straight JDBC via JdbcTemplate and mostly MyBatis for my entity queries.
I've added a logging statement to my ConnectionProvider for Javers, and at the start of the application when it queries for the schema, it pulls 4 connections to check for each of the tables, and then never returns any of them even after the commit from the PlatformTransactionManager.
I understand from https://stackoverflow.com/a/35147884/570291 that it's supposed to participate in the same connection as the current Transaction. Since I'm not using Hibernate/JPA, does that mean I need to implement the connection tracking/etc from MyBatis to the Javers ConnectionProvider to return the same connection (if there is one), and then handle closing (returning to the pool) of that connection at the end of the transaction?
I found DataSourceUtils.getConnection(DataSource) which is a Spring utility class to get a connection from the given DataSource including if it's tied to a current transaction or not as appropriate. Using that in the ConnectionProvider looks like it's done the trick of keeping the connection for the existing transaction.
JaVers won't return connections to application's connection pool for the same reason as it won't call sql commit or rollback.
Managing connactions and transactions is the application's responsibility, not JaVers. We call it passive mode, from Javers doc:
- JaVers doesn’t create JDBC connections on its own and uses connections provided by an application (via ConnectionProvider.getConnection()).
- JaVers philosophy is to use application’s transactions and never to call SQL commit or rollback commands on its own.
Thanks to this approach, data managed by an application (domain objects) and data managed by JaVers (object snapshots) can be saved to SQL database in one transaction.
In JaVers project there is no mybatis support, so you need to implement ConnectionProvider for mybatis on your own.
Proper implementation of ConnectionProvider shouldn't create new sql connection for every getConnection() call. It should return the connection which underlies current application's transaction. Typically, it's implemented using ThreadLocal.
As you mentioned, ConnectionProvider should handle committing transactions and closing connections.
Related
I am trying to understand in background how transaction is mapped to jdbc connection i.e one jdbc connection can be parallely used for multiple spring transactions at the same time or one connection is totally reserved for one transaction at a given time and only released after transaction is complete.
I my opionion one of the best way to understanding how Spring managed transactions is reading Transaction Management Reference Doc.
We are using the JdbcTokenStore from spring-security to persist oAuth2 access tokens. The same application does also heavily rely on spring-data-jpa. Both share a connection pool to a MySQL database.
Jdbc defaults to auto-commit mode and JdbcTokenStore appears to be written with the assumption that auto-commit is on. It never explicitly commits a change.
Spring-data and JPA on the other hand require a transaction for write operations. The application uses the #Transactional annotation.
We are observing the following issue:
Request (1): A client obtains an access token. JdbcTokenStore INSERTs this into the database.
Request (2): Then, the client uses this access token in a subsequent request. This request is rejected since the token cannot be found in the database.
This behaviour could be explained if transaction from request (1) was not yet committed.
I'm not very familiar with the internals of Spring. Is it possible that the following happens?
Some JPA operation acquires JDBC connection #1 from the pool, sets auto-commit=off, executes any number of SQL statements, and, then, commits.
Request (1): JdbcTokenStore acquires the same JDBC connection #1, executes INSERT statement. (This now happens inside a transaction. This is not committed.)
Request (2): JdbcTokenStore acquires a different JDBC connection #2, executes SELECT statement. (This does not see the uncommitted transaction.)
Some JPA operation acquires JDBC connection #1 again and commits. (Now the oAuth token is committed.)
What configuration would avoid this?
While I cannot explain the root cause, we have found a fix: Switching to the HikariCP JDBC connection pool (replacing Tomcat) eliminated all symptoms of the describe issue.
I'm creating a rest service using MyBatis 3.3.1, Spring 4.3, Jersey 2.22 and Oracle 12c. My transactions are being managed by Spring using the DataSourceTransactionManager and the #Transaction annotaion. I am also using a MyBatis pooled data source as my javax.sql.DataSource. What I don't understand if why database sessions are being reused.
In my application, I am setting an oracle client identifier: DBMS_SESSION.SET_IDENTIFIER("my id"). With the debug logging statements, I can see MyBatis creating new sessions for each of the MyBatis sql operations. I also have debug to print out the database session identifier from DBMS_SESSION.UNIQUE_SESSION_ID.
What I don't understand is that if I access my rest endpoint multiple times, the unique session id is the same and the identifier from my last access is still set.
Shouldn't a new oracle session be used every time MyBatis gets a new SQLSession? Why is the oracle session always the same?
Thanks.
Session in Oracle is bound to a connection.
You are using connection pooling so after one rest request is finished the connection is returned to the connection pool. Session is not terminated in this case.
You probably want to clear identifier on returning connection to pool and setting it on retrieving connection from the pool. The exact way to do that depends on the connection pool you are using. For built-in mybatis connection pool see this answer.
I have been researching Spring Data Rest especially for cassandra and one of the questions my coworkers and I had was when does Spring Data connect to the database. We don't always want a rest controller to connect to the database so when does spring establish a connection if say we had a class extend the CRUDRepository? Does it connect to the database during the start of application itself? Is that something we can control?
For example, I implemented this example on Spring's website:
https://spring.io/guides/gs/accessing-data-rest/
At what point in the code does spring connect to the database?
Spring will connect to the DB as soon as the Datasource get initialized. Basically, Spring contexts will become alive somehow (Web listeners, manually calling them) and start creating beans. As soon as it reaches the Datasource, connection will be made and the connection pool will be populated.
Of course the above is based on a normal out of the box configuration and everything can be setup up to your taste.
So unless, you decide to control the connections yourself, DB connections will be sitting there waiting to be used.
Disagree with the above answer.
As part of research i initiated the datasource using a bean configuration and then changed my database password(not in my spring application but the real db username password)
The connection stays for a while and then in some point of time (maybe idle time) it stops working and throws credential exception.
This is enough to say the JPA does not keep the connection sitting and waiting to be used but uses some mechanism to occupy/release the db connection as per the need.
I am using a connection pool and the Spring TransactionTemplate. If you want to shutdown the connection pool first all connection have to be returned to the pool, this means connection.close() has to be called. I have one thread using the TransactionTemplate for some queries and another thread that wants to call some shutdown method on the connection pool, but before doing this it first has to tell the TransactionTemplate to close all connection (actually only returning them to the pool).
How can this be done in Spring to immediately call close on the used connection?
If you are using Hibernate along with Spring please use:
hibernate.connection.release_mode=after_transaction
If you want to release connection just after transaction.
hibernate.connection.release_mode=after_statement
If you want to release connection after each statement
This two settings are the only ways I know that will make used connection being released faster than the default behavior. At least as far as Hibernate is concerned. If you are using other library please describe which.