does #Transactional annotation merge new transaction into exisiting transaction - java

i am having a simple controller /hello which internally calls Repository layer for a transaction using the default propagation level i.e Propagation.REQUIRED.
#Controller
public void hello(data) -> doTransaction(data)
#Repository
#Transactional
public void doTransaction(data){
jdbcTemplateInsertA(data);
Thread.sleep(15*1000);
jdbcTemplateUpdateB(data);
}
as per online docs
REQUIRED is the default propagation. Spring checks if there is an active transaction, and if nothing exists, it creates a new one. Otherwise, the business logic appends to the currently active transaction:
now let's say i hit the API 2 times, with data1 and then data2, before request 1 was finished API was hit 2nd time.
would there be only a single transaction or two separate independent transactions?
Also, i want to know is using #Transactional with jdbcTemplate valid?
i am having doubt on how jdbcTemplate internally gets the same connection object that was used by #Transactional annotation considering pool size >=2.
UPDATE:
You will have a transaction per thread. -> any docs/resources where i can find this?
For 2nd part, let me rephrase my question.
Let's say using hikari pool with size as 5 as per my understanding #Transactional would pick some connection from pool, let's say it picked up connectionId1554 now, when i call jdbc.execute(), how spring ensure that it uses connectionId1554 and not any other available connection from the pool

You will have a transaction per thread. If you have two requests, then you will have two threads (from your web container, like Tomcat), and therefore you'll have two separate transactions.
Based on the code and (lack of) configuration it is hard to tell how you setup your JdbcTemplate. Most likely the connection used by the JdbcTemplate comes from a database connection pool. If you've configured two connections then you can only use two connections and the usage of those connections will block other requests to the database if they are in use. Now, that being said, database connection pools are generally programmed to be super smart and one database connection can be used between multiple database requests/transactions depending on configuration settings.

let's say i hit the API 2 times, with data1 and then data2, before request 1 was finished API was hit 2nd time.
would there be only a single transaction or two separate independent transactions?
Each incoming request to your api will result in an independent transaction being started. If you think this through this makes sense: if you have 2 users each making a request at the same time, you would want each of their requests to be handled independently, it would be odd if both of their requests joined and were handled as a single transaction.
i want to know is using #Transactional with jdbcTemplate valid? i am having doubt on how jdbcTemplate internally gets the same connection object that was used by #Transactional annotation
This depends on how you have configured a Datasource and a connection pool. Are you running this on an appserver like Webpshere, Weblogic or WildFly? They provide Datasource connection pooling integrated with a TransactionManager too.

Related

Is an attached Record thread-safe?

Is an attached jOOQ Record (UpdatableRecord) thread-safe, i.e. can I attach (fetch) a Record in one thread, and store it later in another thread without negative effects? Should I detach it in the original thread and attach it back in the new thread?
I know about the jOOQ manual page about thread-safety of the DSLContext. I'm using the Spring Boot Autoconfiguration of jOOQ, so that should all be thread-safe (with Spring's DataSourceTransactionManager and Hikari pooling).
But the following questions remain:
How does an attached Record behave when a transaction in the original thread is opened, and store() is called in another thread either before or after the original transaction has been committed? Does jOOQ open a new connection every time for each operation?
Would the attached Record be keeping a connection open across threads, which might then lead to resource leaks?
A jOOQ record is not thread safe. It is a simple mutable container backed by an ordinary Object[]. As such, all the usual issues may arise when sharing mutable state across threads.
But your question isn't really about the thread safety of the record.
How does an attached Record behave when a transaction in the original thread is opened, and store() is called in another thread either before or after the original transaction has been committed? Does jOOQ open a new connection every time for each operation?
This has nothing to do with Record, but how you configure jOOQ's ConnectionProvider. jOOQ doesn't hold a connection or even open one. You do that, explicitly, or implicitly, by passing jOOQ a connection via a ConnectionProvider (probably via some Spring configured DataSource). jOOQ will, for each database interaction, acquire() a connection, and release() it again after the interaction. The Record doesn't know how this connection is obtained. It just runs jOOQ queries that acquire and release connections.
In fact, jOOQ doesn't even really care about your transactions (unless you're using jOOQ's transaction API, but you aren't).
Would the attached Record be keeping a connection open across threads, which might then lead to resource leaks?
No, a Record is "attached" to a Configuration, not a connection. That Configuration contains a ConnectionProvider, which does whatever you configured it to do.

Transcations level scope in spring

I'm using Spring Boot 1.4 and trying to understand how does Spring Transaction Management works.
Here is my question:
Lets say I have a service with a method A that is annotated with #Transactional(isolation = SERIALIZABLE) and another method B annotated with #Transactional(isolation = READ_COMMITED).
And then let's imagine that some service X calls these two methods A and B sequentially.
My colleague says that transaction level is set per connection in Spring. Which means that if the same connection from the pool is used for these two sequential calls, then isolation level for both transactions A and B = SERIALIZABLE.
However, to me it seems a bit strange. I would expect that these two transactions would have different level of isolations, because all sql databases allow to set isolation level for a given transaction explicitly.
I was trying to read documentation and couldn't find a place where it would be mentioned that transcation level is assigned to connection.
Can someone judge us on this issue?
If there is no transaction started when calling method A() or B() a new transaction is created when calling the method and gets closed when leaving the method. The used connection returns to pool or gets closed.
This thread explains what happens to the connection when transaction gets closed:
Does Spring close connection after committing transaction?
In case there exists a transaction that wraps both methods, there is only one connection used for both methods; and i guess the isolation level is the one defined by the bigger transaction.

Hibernate internal functioning

I'm working on Spring + Hibernate applications. We have applied transaction for service class methods. My questions
Can hibernate execute all db statements of the service method with single connection/session or it uses multiple connections? If it uses multiple connections is it possible to rollback db statements over multiple connections in case of any runtime exceptions?
Suppose if the service method's business logic execution takes more time than removeAbandonedTimeout value, how does the commit/rollback happens on abandoned connection?
Please correct me if i'm wrong any where. Thanks in advance.
UPDATE:-
If the query takes more time than removeAbandonedTimeout it throws exception. Suppose my service method has two db calls, between those two calls some business logic (with no db calls) is there. Before executing the first query it creates db connection, assume first db call took 1 second, and then the business logic execution took 60 seconds. If the connection is abandoned it this moment (if we set removeAbandonedTimeout to 60 seconds), to execute second db query it creates another connection, right? If the second query execution fails it has to rollback first query as they both share same transaction. How could it happen with abandoned connection?
Hibernate will do what you told it to :
When integrating with spring, it will use spring managed transaction. Check where you are opening / closing tx (use of #Transactional on public method or directly using TransactionTemplate) : all hibernate queries inside will run in the same transaction.
This is a question related to your connection pool (dbcp ?). Do not activate the removeAbandonedTimeout flag : removeAbandonedOnMaintenance : from documentation :
Setting one or both of these to true can recover db connections
from poorly written applications which fail to close connections.
If you are using typical spring / hibernate coding pattern, you are not poorly writting your application (from a database resource point of view), so no need to activate this flag : let your long running thread keep it's transaction. If an operation is running so slow without running any db query (that it would have triggered dbcp cleanup), you have two options :
Don't keep the connection to the database : cut your transaction in two : one before the long running process, one after
If you need to keep the tx open (because you have database lock you do not want to lose for example), try to optimize the code in between using cpu sampling tool for example.
Answers for your questions:
With single connection we can execute all db statements of service.We cannot rollback db statements over multiple connections at a time.
In general the removeAbandonedTimeout value should be set to the longest running query your applications might have.If the removeAbandonedTimeout exceeds and if removeAbandoned = true, the db connections can be recovered.

Spring #Transactional method called by multithread(multi-request)

Java web
Spring MVC framework
In my service level, I wrote a #Transactional method. In that method, I update some data in database and then read the data from the database later.
What surprises me is that when several requests come, inside the same thread, the data change is visible(which is supposed to be), but the data change is not visible in other thread.
Isn't different threads of one method build as one transaction?
And what should I do if I still want to use transaction and I want the same method called in different threads be in one transaction (the change of the data can be seen by each other)?
From Professional Java for Web Applications by Nicholas S. Williams
Using Threads for Transactions and Entity Managers
The transaction scope is limited to the thread the transaction begins in. The transaction manager then links the transaction to managed resources used in the same thread during the life of the transaction. When using the Java Persistence API, the resource you work with is the EntityManager. It is the functional equivalent of Hibernate ORM’s Session and JDBC’s Connection. Normally, you would obtain an EntityManager from the EntityManagerFactory before beginning a transaction and performing JPA actions. However, this does not work with the Spring Framework model of managing transactions on your behalf.
The solution to this problem is the org.springframework.orm.jpa.support.SharedEntityManagerBean. When you configure JPA in Spring Framework, it creates a SharedEntityManagerBean that proxies the EntityManager interface. This proxy is then injected into your JPA repositories. When an EntityManager method is invoked on this proxy instance, the following happens in the background:
➤➤ If the current thread already has a real EntityManager with an active transaction, it delegates the call to the method on that EntityManager.
➤➤ Otherwise, Spring Framework obtains a new EntityManager from the
EntityManagerFactory, starts a transaction, and binds both to the current thread. It then delegates the call to the method on that EntityManager. When the transaction is either committed or rolled back, Spring unbinds the transaction and the EntityManager from the thread and then closes the EntityManager. Future #Transactional actions on the same thread (even within the same request) start the process over again, obtaining a new EntityManager from the factory and beginning a new transaction. This way, no two threads use an EntityManager at the same time, and a given thread has only one transaction and one EntityManager active at any given time.
(I paraphrased it a little the above piece)
I think its self explanatory and answers your question. But I would like to add that, if you were not to use Spring MVC then you would have gotten the session using SessionFactory in Hibernate. Hibernate Sessions represent the life of a transaction from start to finish. Depending on how your application is architected, that might be less than a second or several minutes; and in a web application, it could be one of several transactions in a request, a transaction lasting an entire request, or a transaction spanning multiple requests. A Session, which is not thread-safe and must be used only in one thread at a time, is responsible for managing the state of entities.
you may want to play with isolation parameter of#Transactional annotation. Spring by default uses.. hm.. DEFAULT which is set by database, so may be different. You can try to use: READ_UNCOMMITTED. More info: http://www.byteslounge.com/tutorials/spring-transaction-isolation-tutorial

Does beginTransaction in Hibernate allocate a new DB connection?

Just wondering if beginning a new transaction in Hibernate actually allocates a connection to the DB?
I'm concerned b/c our server begins a new transaction for each request received, even if that request doesn't interact with the DB. We're seeing DB connections as a major bottleneck, so I'm wondering if I should take the time narrow the scope of my transactions.
Searched everywhere and haven't been able to find a good answer. The very simple code is here:
SessionFactory sessionFactory = (SessionFactory) Context.getContext().getBean("sessionFactory");
sessionFactory.getCurrentSession().beginTransaction();
sessionFactory.getCurrentSession().setFlushMode(FlushMode.AUTO);
thanks very much!
a
According to the section 11.1. Session and transaction scopes of the Hibernate documentation:
A SessionFactory is an
expensive-to-create, threadsafe
object, intended to be shared by all
application threads. It is created
once, usually on application startup,
from a Configuration instance.
A Session is an inexpensive,
non-threadsafe object that should be
used once and then discarded for: a
single request, a conversation or a
single unit of work. A Session will
not obtain a JDBC Connection, or a
Datasource, unless it is needed. It
will not consume any resources until
used.
In order to reduce lock contention in
the database, a database transaction
has to be as short as possible. Long
database transactions will prevent
your application from scaling to a
highly concurrent load. It is not
recommended that you hold a database
transaction open during user think
time until the unit of work is
complete.
Now, to answer your question:
getting a Session does not immediately acquire a connection (the connection is lazy loaded)
but calling beginTransaction() will cause the load of the connection for the given Session
subsequent calls will reuse the same connection
Look at org.hibernate.impl.SessionImpl#beginTransaction() and go through the code for more details.
(Updated per Pascal Thivent's comment)
Each Session creates a database connection if there is a need for that - e.g. if a transaction is started. The connection is not opened with the mere creation of the session.
To overcome this, you can use a connecetion pool so that connections are reused. Or you can make sure (as it appears you did) that no transaction is started automatically.
(This discusses read-only transactions. Take a look.)

Categories