Container managed transaction boundary in SFSB - java

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.

Related

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

Put #Transactional annotation to 'onMessage' method

I find the similar question here but didn't find a clear answer on the transaction management for back end (database)
My current project is to create producer/consumer and let consumer to digest JMS message and persist in database. Because the back end of the application is managed by JPA, so it is critical to maintain the whole process transactional. My question is what is the downside if place #Transactional annotation on the classic onMessage method? Is there any potential performance challenge if do so?
The only problem may be if the whole queue process takes too long and the connection closes in the middle of the operation. Apart of this, if you enable the transaction for the whole queue process rather than per specific services methods, then theoretically the performance should be the same.
It would be better to enable two phase commit (also known as XA transaction) for each queue process. Then, define each specific service method as #Transactional and interact with your database as expected. At the end, the XA transaction will perform all the commits done by the #Transactional service methods. Note that using this approach does affect your performance.

Multiple transactions in a single hibernate session (with Spring)

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.

Whats the best practice around when to start a new session or transaction for batch jobs using spring/hibernate?

I have set of batch/cron jobs in Java that call my service classes. I'm using Hibernate and Spring as well.
Originally the batch layer was always creating an outer transaction, and then the batch job will call a service to get a list of objects from the DB w/ the same session, then call a service to process each object separately. Theres a tx-advice set for my service layer to rollback on any throwable. So if on the 5th object theres an exception, the first 4 objects that were processed gets rolled back too because they were all part of the same transaction.
So i was thinking this outer transaction created in the batch layer was unnecessary. I removed that, and now i call a service to get a list of objects. THen call another service to process each object separately, and if one of those objects fail, the other ones will still persist because its a new transaction/session for each service call. But the problem I have here now is after getting a list of objects, when i pass each object to a service to process, if i try to get one of the properties i get a lazy initialization error because the session used to load that object (from the list) is closed.
Some options i thought of were to just get a list of IDs in the batch job and pass each id to a service and the service will retrieve the whole object in that one session and process it. Another one is to set lazy loading to false for that object's attributes, but this would load everything everytime even if sometimes the nested attributes aren't needed.
I could always go back to the way it was originally w/ the outer transaction around every batch job, and then create another transaction in the batch job before each call to the service for processing each individual object...
What's the best practice for something like this?
Well I would say that you listed every possible option except OpenSessionInView. That would keep your session alive across transactions, but it's difficult to implement properly. So difficult that it's considered an AntiPattern by many.
However, since you're not implementing a web interface and you aren't dealing with a highly threaded environment, I would say that's the way to go. It's not like you're passing entities to views. Your biggest fear is an N+1 call to the database while iterating through a collection, but since this is a cron job, performance may not be a major issue when compared with code cleanliness. If you're really worried about it, just make sure you get all of your collections via a call to a DAO who can do a select *.
Additionally, you were effectively doing an Open Session In View before when you were doing everything in the same transaction. In Spring, Sessions are opened on a per transaction basis, so keeping a transaction open a long period of time is effectively the same as keeping a Session open a long period of time. The only real difference in your case will be the fact that you can commit periodically without fear of a lazy initialization error down the road.
Edit
All that being said, it takes a bit of time to set up an Open Session in View, so unless you have any particular issues against doing everything in the same transaction, you might consider just going back to that.
Also, I just noticed that you mentioned opening a transaction in the batch layer and then opening "mini transactions" in the Service layer. This is most emphatically NOT a good idea. Spring's annotation driven transactions will piggyback on any currently open transaction in the session. This means that transactions that are supposed to be read-only will suddenly become read-write if the currently open transaction is read-write. Additionally, the Session won't be flushed until the outermost transaction is finished anyways, so there's no point in marking the Service layer with #Transactional. Putting #Transactional on multiple layers only lends to a false sense of security.
I actually blogged about this issue some time ago.

getCurrentSession hibernate in web

I am writing a web based application with hibernate and jsp/servlet. I have read about the sessionFactory.getCurrentSession and sessionFactory.openSession methods. I know the basic difference between them (using getCurrentSession you don't have to close the connection and when you commit the transaction, your session will automatically close). According to the my understanding, we should opt for getCurrentSession and do it through session-per-request.
Let's consider the following scenario:
Method A calls getCurrentSession and got the current session
In Method A, a transaction is started using the session from step 1
Method A calls Method B, which also has getCurrentSession and starts a transaction
Method B commits its transaction
Control returns to method A and it also commits the transaction
Now my questions are
Will the session found in step 1 and step 3 will be the same session?
If the answer for the question 1 is yes, then how would it handle the commit in step 4? Ideally it should close the session there itself and should throw an exception at step 5.
If the answer for the question 1 is no, then how do you handle such a scenario?
Will the session found in step 1 and step 3 will be the same session?
They should be the same, that's somehow part of the contract of getCurrentSession() and you'll get the Session bound to the thread as long as the unit of work has not been completed (i.e. a transaction has been committed or rolled back). Java Persistence with Hibernate puts it like this (p.481):
All the data-access code that calls getCurrentSession() on the global shared
SessionFactory gets access to the same current Session — if it’s called in the
same thread. The unit of work completes when the Transaction is committed (or rolled back). Hibernate also flushes and closes the current Session and its persistence context if you commit or roll back the transaction. The implication here is that a call to getCurrentSession() after commit or rollback produces a new Session and a fresh persistence context.
And you might also want to read what the javadoc of Session#beginTransaction() says.
If the answer for the question 1 is yes, then how would it handle the commit in step 4. Ideally it should close the session there itself and should give error at step 5.
Step 4 shouldn't be a problem, the Session will be flushed, the Transaction will be committed and the Session closed. But I expect step 5 to fail wih aTransactionException (that's my bet). But let me quote the javadoc of Transaction:
A transaction is associated with a Session and is usually instantiated by a call to Session.beginTransaction(). A single session might span multiple transactions since the notion of a session (a conversation between the application and the datastore) is of coarser granularity than the notion of a transaction. However, it is intended that there be at most one uncommitted Transaction associated with a particular Session at any time.
As underlined above, we are discussing around something that shouldn't happen (i.e. a design problem).
I don't have an answer for your scenario because I would not implement it that way as it seems to be asking for trouble. Instead, I'd start the transaction in C, where C invokes A and B, and have C issue the commit. Skeletally:
public void c(...) {
try {
transaction.begin();
a();
b();
transaction.commit();
catch (Exception e) {
transaction.rollback();
}
}
So here, a() and b() do not commit or rollback - how do they know the entire business task has been completed? They could throw an exception or perhaps return a boolean to tell the caller that something is amiss and a rollback is needed.

Categories