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
Related
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.
I am working on a legacy application. We are moving it from JDBC to Spring 3.2 + Hibernate 4.1.12 + JTA 2 with declarative transactions. I see that the Container-Managed Transactions (CMT) are transacting and rolling back as one would expect. We are using Infinispan as the second level cache (2LC). There is one wrinkle...
There is a portion of the code with a different entry point that is run in a different thread and uses programmatic transactions or Bean-Managed Transactions (BMT). In the BMT path, I see that in the underlying service layer, which is using CMT, the transactions are joining with the BMT as one would hope and expect.
The persistence unit, data source, etc. are the same for both entry points. In both cases, the Hibernate autoflush code is aware that there is a transaction and flushes to the database driver. In the CMT entry point, the database driver holds the data until told to commit or rollback. In the BMT path, the data is pushed into the database on flush – the later commit or rollback has no effect or apparent meaning. The transaction manager is the JtaTransactionManager. The JtaTransactionManager is defined in a #Configuration class with #EnableTransactionManagement to enable the CMT rather than the <tx:annotation-driven/> element.
The singleton JtaTransactionManager bean is wired with the ajuna UserTransaction and TransactionManager via jtaPropertyManager.getJTAEnvironmentBean().getTransactionManager() and jtaPropertyManager.getJTAEnvironmentBean().getUserTransaction(). Both the UserTransaction and TransactionManager are prototype #Bean definitions.
I am able to confirm the data is in or not in the database by a query from another query tool to verify the behavior while debugging.
When I am unit testing, the data commits and rolls back as expected for both the BMT and the CMT entry point.
The BMT is managed by a class that has the transaction begin and end in different methods. It also has methods that perform the actual unit of work. The transactions for the BMT are initiated with the PlatformTransactionManager, not the TransactionTemplate. The class is driven by another class that has the logic to manage the logic flow. I know that the transactions are beginning and ending as expected. When reading various other discussion, It seems implied that the transactional control should be within a single method. I would agree that this would be preferred but is it essential?
If a CMT-managed servlet in Spring spawns a new Thread and starts the thread with a plan thread.start(), is it reasonable to expect that a BMT within that new Thread would be able to manage its transactions as described above?
The datasource is retrieved by JNDI. Using XA or non XA does not influence the outcome.
I am unable to post the code.
As a reference, here is the link to the Spring 3.1 docs on transaction in chapter 11.
Added 2013/10/04 - I see that Spring uses the JtaTransactionManagerBeanDefinitionParser to construct the desired JtaTransactionManager based on the perceived container. When this is used, the JTA transaction manager will set into itself in the afterPropertiesSet the UserTransaction, TransactionManager, and TransactionSynchronizationRegistry.
It appears that I do actually still leak data in the CMT but that it is hard to perceive/observe this without a debugger or forcing an error unnaturally since the transactions typically commit.
It appears that my issue is that I have partially bypassed the JCA such that the JCA is using a different TransactionManager.
Partial Answer - Because I have seen this transact properly in a mix of CMT and BMT, I know that it is possible to have the BMT transaction started in one method and committed in another.
The question remains: If a CMT-managed servlet in Spring spawns a new Thread and starts the thread with a plan thread.start(), is it reasonable to expect that a BMT within that new Thread would be able to manage its transactions as described above?
From JTA 1.1 Specification (http://download.oracle.com/otn-pub/jcp/jta-1.1-spec-oth-JSpec/jta-1_1-spec.pdf) section 3.1, it is clear that the transaction is bound to the thread. This is managed by the TransactionManager. One should be able to expect the thread to be able to perform actions within a transactional context if the thread is the one that created the transaction.
Note that the support of nested transactions is optional as cited in the same portion of the JTA specification.
The actual issue I was encountering was that the managed datasource was using a different instance of the transaction manager than we had as a bean in the application. Changing the application code to do a JNDI lookup of the container-provided TransactionManager allowed the managed datasource to participate in the same transaction as the application.
I have read in the book that:
Typically, the container begins a transaction immediately before an enterprise bean method starts. It commits the transaction just before the method exits.
Suppose my stateful EJB has exposed 3 business methods and the client calls these 3 methods sequentially and want wants to run these 3 methods within a single transaction. These methods would be called across multiple requests.
Now the spec says that the transaction is committed just before the method exits. How will I be able to rollback the whole transaction, if my 1st method is successful and 2nd (or 3rd) method fails?
Please note that I don't want to use create my own transaction boundary.
Any help or the pointer in the right direction would be highly appreciated.
You are using a stateful session bean to act as a buffer. And you want a transaction around multiple calls.
From a design perspective, it's OK, if the transaction is started and committed/rollbacked from a single request (from within a single HttpServletRequest for example). In this case you can use a UserTransaction to span the transaction over multiple calls to an EJB. But a UserTransaction is bound to the current thread, so it might be difficult to pass it to the next request.
If you start and commit from different requests, you lose control over the duration of the transaction: Now a client controls the transaction. If that client crashes, the transaction won't be rolled back until the transaction timeout is reached. So the recommendation in this case is to buffer in a HttpSession for example. If all data has been collected, call a (stateless) EJB to persist it.
Create a method in the bean that calls all the other 3 methods. Then they'll be in the same transaction.
Is it possible to model the following using Hibernate + Spring.
Open session
Begin transaction
Do some work
Commit
Begin transaction
More work
Commit
Close session
I use the Spring TransactionTemplate which does both session + transaction lifetime scoping.
The reason is that sometimes I have a few stages in a business process and I would like to commit after each stage completes. However I would like to continue using the same persistent objects. If I have a separate session per transaction then I get transient/detached exceptions because the original session was closed.
Is this possible?
Yes, Hibernate's Sessions can begin and commit several transactions. What you need to do is to store open session somewhere, then reuse it. Note, that Session is not a thread-safe object, but if you're sure it won't have problems with concurrency, what you need is just to use TransactionSynchronizationUtils to bind a session to the thread resources and then unbind it when desired, you can find an example here or you can take a look at OSIV and its standard implementations.
This is a very complicated thing, it's much easier and thus desirable that you close your session right away and don't reuse it, because it may bring troubles:
The objects inside of cache are not automatically evicted, thus your Session will grow in size until OutOfMemory.
The objects inside of session are not flushed unless they are dirty, thus the chance that object was changed by another user is larger and larger. Ensure that only a single user is going to change writable objects.
If some exception happens during one of steps, you have to ensure you close the session. After exception occurred inside of Session, this object is not reusable.
If transaction was rolled back, the session is cleared by Spring, thus all your objects become detached. Make sure your discard everything if at least one of transactions was rolled back.
You could achieve this using the OpenSessionInView pattern. Spring provides a javax.servlet.Filter implementation which you could use if you're working in a servlet environment (question doesn't say so). This will ensure that your Hibernate session is kept open for the duration of the request rather than just for an individual transaction.
The Javadoc on this class is pretty comprehensive and might be a good starting point.
I am working on an EJB3 application with mainly stateless session beans (SLSB). They use container managed transactions (CMT).
I want the beans to be aware of the transactions (for logging, etc). I can implement the javax.ejb.SessionSynchronization to do this. I find that I can register a javax.transaction.Synchronization in a default interceptor also to get similar callbacks.
Are there any dis/advantages to using one over the other?
Multiple SLSB of the same type can be involved in the same transaction. As soon as a method exits, the SLSB is returned to a pool for use by the next invocation, so it is not safe for an SLSB instance to be "aware" of a transaction: by the time it is notified, the bean might be in use in another transaction.
As for SFSB, I would say there is no advantage between the two approaches in theory. However, the EJB container might be using Synchronization for various internal tasks, so using SessionSynchronization would allow the EJB container to have more control over the timing of the callbacks with respect to its own operations.
I just tried to use the javax.ejb.SessionSynchronization interface with a stateless session bean and was confused not to get any calls of the three implemented methods. Then I saw this comment in the javax.ejb.SessionSynchronization JavaDoc:
Only a stateful session bean with container-managed transaction demarcation can receive session synchronization notifications. Other bean types must not implement the SessionSynchronization interface or use the session synchronization annotations.
See also this thread for some more background. So my conclusion is that making stateless session beans transaction-aware using CMT can NOT be achieved with javax.ejb.SessionSynchronization.