CDI Event and XA transaction - java

I'm using Java EE 6.
I'd like to trigger an action upon successful commit of a transaction. For now, my plan is to use a CDI transactional event within an EJB:
#Asynchronous
public void triggerAction(#Observes(during = TransactionPhase.AFTER_SUCCESS) MyEvent myEvent){
// Do something with the event
}
The transaction triggering the event can be involved in a XA distributed transaction.
At which phase of the two phase commit will the observer be called ?
The documentation states:
An after success observer method is called during the after completion phase of the transaction, only when the transaction completes successfully.
I'm not sure what this implies when using distributed transactions.
Further, is there any warranty that the data is already in DB (i.e. can my observer method be called when the decision to commit is reached, but the data are not yet persisted in DB ?).

Unfortunately, CDI 1.x does not define the behavior of events in async call stacks. The behavior you will see will be container specific, including some containers that invoke this method synchronously instead of async. CDI 2.0 is introducing an async observer for events.

the XA transaction manager is responsible for 'applying' XA semantics, meaning it has to go through the 2 Phase Commit (dialog) with all the involved parties (distributed parties) and then it will commit and consider (if no errors) it as done.
In you case, the observer will be called when the data in the db will be commited in the context of the transaction and not in any previous or interim state.

Related

Canceling a transaction through API

I'm developing a system that contains multiple microservices operating on the same database, which isn't ideal but is done for the sake of legacy support. As we refactored the old system we split old, transactional functionality into separate microservices, which led us to have distributed transactions now that must be handled in some way. We're using Spring boot.
As it usually goes, we have a microservice A calling microservices B and then C, we need a way to rollback transaction B if transaction C throws an error.
I've read on 2PC and Saga approaches, I was wondering if there is a way to implement a somewhat simpler variation of 2PC approach. It would need to support the following functionality.
1)Microservice endpoint is called, it calls a #Transactional service which creates a transaction. A special parameter is passed that tells the TransactionManager to keep the transaction "hanging" for some time (say, 5 seconds)
2)In those 5 seconds, another call can be made that either confirms or rolls back the transaction
3)If the time elapses (times out), default handling for the transaction is applied (either rollback or commit)
4)If the special parameter isn't passed in, transactions behave as if they are not distributed
5)API calls are still asynchronous
Simple example:
1)Service A endpoint "createResource" is called with parameter "hangTransaction=true"
2)Service A returns status 200
3)Service B endpoint "registerResource" is called
4)Service B returns status 500
5)Service A endpoint "createResource" is called with parameter "transactionValid=false"
6)Service A rolls the transaction back and returns status 200
7)There are no changes to DB after this
There would of course be additional parameters sent (transaction ID for example), the example is simplified.
Is there some way to control the TransactionManager in a way that allows the transaction to persist between API calls?

What is a transaction boundary in hibernate

I have 2 questions related to each other
Q1 What exactly is a transaction boundary in hibernate/Spring Data JPA.
I am new to JPA , so please give a very basic example so I can understand as I tried to read multiple blogs but still not very clear.
Q2 And on top of it, what does this mean-
In hibernate, persist() method guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries, save() method does not guarantee the same.
What is outside and inside of a transaction boundary and how executions are performed outside boundaries?
A transaction is a unit of work that is either executed completely or not at all.
Transactions are fairly simple to use in a typical relational database.
You start a transaction by modifying some data. Every modification starts a transaction, you typically can't avoid it. You end the transaction by executing a commit or rollback.
Before your transaction is finished your changes can't be seen in other transactions (there are exceptions, variations and details). If you rollback your transaction all your changes in the database are undone.
If you commit your changes your changes become visible to other transactions, i.e. for other users connected to the same database. Implementations vary among many other things if changes become visible only for new transactions or also for already running transactions.
A transaction in JPA is a database transaction plus additional stuff.
You can start and end a transaction by getting a Transaction object and calling methods on it. But nobody does that anymore since it is error prone. Instead you annotate methods with #Transaction and entering the method will start a transaction and exiting the method will end the transaction.
The details are taken care of by Spring.
The tricky part with JPAs transactions is that within a JPA transaction JPA might (and will) choose to delay or even avoid read and write operations as long as possible. For example when you load an entity, and load it again in the same JPA transaction, JPA won't load it from the database but return the same instance it returned during the first load operation. If you want to learn more about this I recommend looking into JPAs first level cache.
A transaction boundary it's where the transaction starts or is committed/rollbacked.
When a transaction is started, the transaction context is bound to the current thread. So regardless of how many endpoints and channels you have in your Message flow your transaction context will be preserved as long as you are ensuring that the flow continues on the same thread. As soon as you break it by introducing a Pollable Channel or Executor Channel or initiate a new thread manually in some service, the Transactional boundary will be broken as well.
some other people ask about it - look it up.
If you do not understand something write to me again more accurately and I will explain.
I really hope I helped!

Will a TransactionAttributeType.REQUIRES_NEW annotated method run on a new Thread?

According to documentation, in container managed transactions, if a method is annotated with TransactionAttributeType.REQUIRES_NEW attribute, will suspend any client transaction, delegate the call to this method/ create a new transaction, and resume to previous transactions after the new one has been completed.
So this actually means, that no new thread is created, and that the previous transaction is on a "wait" state until the new one is has been finished?
As stated in the Java-Doc:
If a client calls with a transaction context, the container suspends the association of the transaction context with the current thread before starting the new transaction and invoking the method. The container resumes the suspended transaction association after the method and the new transaction have been completed.
It's not abandoning the thread or creating a new one, it's only releasing the association to the transaction and recreating it afterwards. If it would create a new thread, there would be no need to remove the association because it was never made.
Container managed transactions means JTA and JTA specifications does not allow transactions to span across multiple threads. Each JTA transaction is associated with an execution thread, so it means that at most one transaction can be active at any given time. Note that multiple transactions can be associated with a single thread, but again only one can ever be active at a given time.
As JTA does not support nested transactions, it means that if one transaction is active, it is not possible to start another one in the same thread, until the first transaction commits or rolled back (or timed out, causing again rollback), thus releasing transaction association with the current thread.
What happens behind the scenes when method with transactional attribute REQUIRES_NEW is called with the transactional context? First, JTA temporarily suspends the transaction that is currently associated with the calling thread by calling it is internal API, particularly it calls TransactionManager.suspend(). (If calling thread is not associated with any transaction (i.e. method was called with transactional attribute of NOT_SUPPORTED or without transactional context) a null object reference is returned) and obtaining Transaction object. This Transaction object will be passed to TransactionManager.resume() method to re-associate the transaction context with the calling thread once above mentioned REQUIRES_NEW method completes. Whether on same or another thread depends on JTA implementation, as specification does explicitly require it to be one way or the other.
Answering your question - the only way for JTA to fulfill transactional attribute REQUIRES_NEW when called in transactional context is to suspend the transaction from a thread and resume it later on the same or another thread. When it will be resumed? Remember that REQUIRES_NEW attribute basically means is that annotated method always have to be in its OWN TRANSACTION, which in turn means that the method should be committed or rolled back independently of methods further up the call stack. Suspended transaction will be resumed, once called method with transactional attribute REQUIRES_NEW commits or rolled back.
As a side notes, as you may probably know, there is no way for Bean Managed Transaction to suspend a transaction, you can't do it programatically. Only JTA can do this using an it's internal transaction management API and you can achieve this declaratively by using CMT and transaction attributes. Also note that this attribute can lead to excessive transaction overheads is overused.

EJB : Two stateless objects use two different transaction

I would like to ask question regarding EJB. I am using eclipselink of JPA.
There is two stateless objects in a stateless object in my code.
Is that possible this two stateless object use two different transactions?
Absolutely. You may find it useful to read about the transaction attributes.
If the called method in your first class (say StatelessFirst) has a transaction type REQUIRED (the default) or REQUIRES_NEW, when it is called it will initiate a new transaction. If this then calls a method in your second class (say StatelessSecond) with transaction type REQUIRES_NEW, the first transaction is suspended and a second transaction is initiated while the second method executes. When the method in StatelessSecond completes, the second transaction commits, the first transaction is reinstated, and control is passed back to StatelessFirst.
To make the first transaction commit before StatelessSecond is called, you can use bean-managed transactions. This gives you full control over the transaction management, so in StatelessFirst you can begin a transaction, then commit then call StatelessSecond. If you go with this approach, note that you can't perform nested transactions in BMT.
One other option which allows you to stay within CMT would be to pull the transactional behaviour out of StatelessFirst into a third EJB, with REQUIRES_NEW. Then the pattern is:
Client calls StatelessFirst, which initiates transaction A
StatelessFirst calls NewBean, which initiates transaction B, and performs some work
NewBean commits transaction B and returns
StatelessFirst calls StatelessSecond, which initiates transaction C, and performs its work
StatelessSecond commits transaction C and returns
StatelessFirst completes, and commits transaction A (which doesn't have any changes anyway)

JTA Transactions on asynchronous EJBs

I'm thinking to use in our Java EE 6 applications the async features of EJB 3.1. My only concern is how JTA transactions will be managed ? F.e. what happens if I mix an async call with an EJB sync call ? will they join the same transaction or async transactions live in a tx context of their own ?
Thannks!
If you do not annotate anything, they will be in the same transaction. An Asynchronous session bean behaves the same as a synchronous one when it comes to transaction propagation between them.
For example, if you have an async method from which you call an sync method of another EJB, then the transaction will propagate as between synchronous EJB methods (i.e by default they will be executed in the transaction).
The only difference is related to the propagation of the client transaction context. The specification says:
Client transaction context does not propagate with an asynchronous
method invocation. From the Bean Developer’s view, there is never a
transaction context flowing in from the client. This means, for
example, that the semantics of the REQUIRED transaction attribute on
an asynchronous method are exactly the same as REQUIRES_NEW.

Categories

Resources