ProstDev ProstDev
Guides Oct 12, 2021 · 9 min read

How to Handle Single and XA (Extended Architecture) Transactions in MuleSoft

A transaction is a group of operations where all the steps are needed to be successful to commit a result. If any one of the intermediate steps fail, the whole chain of steps fails collectively. In this post, we'll learn how to implement Single and XA transactions using MuleSoft.

By Soumyajit Sinha
How to Handle Single and XA (Extended Architecture) Transactions in MuleSoft

“Transaction” is a word that is used way too frequently in our daily lives. We use it whenever we are engaged in purchasing or selling any commodity. In our daily lives, a transaction signifies an instance of buying or selling something. Also, a transaction can be deemed as completed only upon the overall completion of the buying/selling activity along with the monetary affair associated with it.

In the software industry, we use the word ‘transaction’ in multiple areas. Predominantly, it is used while discussing SQL queries. Transactions make up a very important component of any software development life cycle (SDLC). Let’s see how transactions are changing lives!

A transaction is a group of operations where all the steps are needed to be successful to commit a result. If any one of the intermediate steps fail, the whole chain of steps fails collectively.

Let’s understand it using a pictorial reference.

Two transaction flowcharts: one committing all four steps, one rolling back after an error at step 2

Let’s consider a case where we have a chain of steps that represents the following:

StepActionTable involved
Step 1This is a SQL fetch operation that fetches information on a certain dealTable A
Step 2This is a SQL insert operation that inserts the new record after consolidating the data received in the previous stepTable A
Step 3This is a SQL delete operation that deletes the previously available recordTable A
Step 4This is a SQL update operation that updates the amount update in another tableTable B

We want all the steps to be completed collectively or else we want none of them to happen. In layman’s terms, we want the event to be committed only if all the steps are successful. If any intermediate step fails, we do not want the event to be committed and we do not want any step to be actioned upon.

In the above picture, we have encapsulated these 4 steps in a transaction. The first diagram starts and completes without any errors and gets committed.

But in the second diagram, we can see that in step 2 we encountered a certain error. Now, we don’t want the event to be committed. This is made possible by the transaction action. It will make sure that all the steps are rolled back to the initial state from which the event was kicked off.

Now that we are clear on what transaction is and how it helps in software development, let’s indulge ourselves in bringing it to life in MuleSoft.

MuleSoft supports two types of transactions:

  • Single resource
  • XA transactions (Extended Architecture)

Let’s talk about them in detail.

Single Resource transactions

Let’s consider a Mule flow where we are dealing with a single mode of data transaction. Consider our flow is having only JDBC affairs or JMS activities or VM Queues.

We have created a flow in which we are dealing with 2 tables connecting to the same database. This is how the flow looks like:

single-resource-example flow in a Try scope: numbered Select, Insert, Delete, and Update database operations

Here, the following database actions are carried out:

StepActionTable involved
Step 1A JDBC select operation (1) fetches information on a certain publicationTable A
Step 2A JDBC insert operation (2) inserts the new record after consolidating the data received from the user & the data received in the previous fetch operationTable A
Step 3A JDBC delete operation (3) deletes the previously available record in the table in which data is inserted in step 2Table A
Step 4A JDBC update operation (4) updates the author details of the publication in another table in the same databaseTable B

Here, we have encapsulated all the JDBC components within a TRY block.

Why use the TRY block?

Try block is helping us to enforce the transaction on the JDBC operations by acting as the initiator of a transaction thread. The JDBC components simply connect themselves to the transaction initiated by the try component.

In a try block, you can set how you want to deal with transaction action.

Try scope settings with the Transactional action dropdown open showing ALWAYS_BEGIN, BEGIN_OR_JOIN, INDIFFERENT

The try-block provides us the following transaction actions:

Transactional actionDescription
ALWAYS_BEGINIt will always initiate a new transaction
BEGIN_OR_JOINIt will initiate a new transaction if there are no preceding transactions. In case there is a transaction that has already been set up, the try block will join that transaction
INDIFFERENTIt will be neutral. It will neither create a transaction nor join an existing transaction

For more information on the Transactional Actions, please refer to the official documentation.

Once you have defined the transaction action, you can go ahead and set the transaction type.

Try scope settings with the Transaction type dropdown open showing LOCAL and XA options

The try-block provides us the following transaction actions:

Transaction typeDescription
LOCALSingle Resource
XAExtended Architecture Transactions

In our case, since we are dealing with Single Resource (only JDBC operation), we will be selecting the LOCAL transaction type and we will let the try-block initiate the transaction.

Once the transaction has been kicked off by the try block, all we need to do is to instruct our JDBC components to JOIN this transaction. We can do that simply by going to the “advanced” section of the JDBC operator.

Database operation Advanced tab with the Transactional action dropdown set to ALWAYS_JOIN

We will select ALWAYS_JOIN as the transactional action so that it joins the transaction initiated by the try block earlier. We will be selecting the same option for all our JDBC components.

Once this is done, we can go ahead and deploy our code.

Extended Architecture transactions

Let’s consider a case when we need to deal with multiple data exchange sources. For example, if we need to use a JMS broker along with a JDBC operation and VM queues and we need all of these operations to be performed atomically.

We want all these operations to be performed following the ACID (Atomicity, Consistency, Isolation & Durability) concept.

ACID propertyDescription
AtomicityThe entire transaction should be performed at a single go with all the components being successful
ConsistencyThe results from all the operations should be consistent across all the sources/data exchanges
IsolationThe operations should be performed separately and sequentially. There should be no overlap
DurabilityOnce the transaction is committed, then under no circumstance it should be rolled back

The XA transaction follows a 2-Phase-Commit protocol.

The first phase of the 2PC is used to check whether all the actions/steps (we can consider these steps to be our JDBC/JMS components) in a transaction have been successfully completed.

If all of them pass or get completed, the transaction manager commits the transaction and writes the corresponding completion logs which can be found in a file with a name ending with “tx-logs” in the .mule folder of your workspace directory.

If any of the components fail execution, the transaction manager rolls back the entire transaction.

We will be using Bitronix Transaction Manager as our transaction manager to accomplish this. We can add this in our Global Elements section in Anypoint Studio.

Two dialogs: choosing the Bitronix Transaction Manager global type, then its properties with OK highlighted

To add Bitronix Transaction Manager, head on to the Global Elements section and search for Bitronix (left image). Once done, another window (right image) will pop up. Click on “OK” and you are all set!

Let’s try this out in Anypoint Studio. This is how the flow will look like in this case:

extended-architecture-example flow adding a fifth step to publish to a JMS topic across two databases

Here, the following database actions are carried out:

StepAction
Step 1A JDBC select operation (1) fetches information on a certain publication from a table in Database A
Step 2A JDBC insert operation (2) inserts the new record after consolidating the data received from the user & the data received in the previous fetch operation in a table in Database A
Step 3A JDBC delete operation (3) deletes the previously available record in the table in which data is inserted in step 2 from a table in Database A
Step 4A JDBC update operation (4) updates the author details of the publication in another table in the Database B
Step 5Publish the author update details in a JMS Queue (5)

Compared to what we have done in our implementation of Single Resource transaction, we will do the same thing with the try block, JDBC & JMS components. The only difference is that we have to intimate Mule that we will be using XA transactions.

To do that, we have to select XA as “transaction type” in the Try scope settings.

For JDBC & JMS components, this is configurable in their Global Settings.

In the Database connection config palette, we can head to the “transactions” section where we will have a tick-box to turn the XA transaction on.

Database Config Transactions tab with the Use XA Transactions checkbox ticked

In the JMS connection config palette, we need to scroll down to the “Connection Factor” section. Select “Edit inline” for the “Factory configuration”. Then we will have a tick-box to turn the XA transaction on.

JMS Config with No caching strategy and the Enable xa checkbox ticked in the connection factory

Note

For JMS Connection, XA will not work when caching is activated. Please select “No caching” as the Caching Strategy and then click on “Test Connection…” to see whether the connection is successful or not.

We will select ALWAYS_JOIN as the transactional action so that it joins the transaction initiated by the try block earlier. We will be selecting the same option for all our JDBC and JMS components.

Once this is done, we can go ahead and deploy our code.

So, now we have the knowledge of what a transaction is and how to set up one in MuleSoft. Apart from that, we have talked about the various kinds of transactions and how to consider one based on the requirement.

Following this up will be an article in which we will take a deeper dive into other intricacies of transactions.

Thank you!!

FAQs

Frequently asked questions about this post.

  • What is a transaction in MuleSoft?

    A transaction is a group of operations where all the steps need to be successful to commit a result. If any one of the intermediate steps fails, the whole chain of steps fails collectively, and the transaction action rolls everything back to the initial state from which the event was kicked off so that none of the steps are committed.

  • What types of transactions does MuleSoft support?

    MuleSoft supports two types of transactions: Single Resource (a single mode of data transaction, such as only JDBC affairs, only JMS activities, or only VM Queues) and XA (Extended Architecture) transactions, which you use when you need to deal with multiple data exchange sources atomically, such as a JMS broker along with a JDBC operation and VM queues.

  • Why do you use a Try block for transactions in MuleSoft?

    The Try block enforces the transaction on the JDBC operations by acting as the initiator of a transaction thread, and the JDBC components simply connect themselves to the transaction initiated by the Try component. In the Try block you set both the transactional action and the transaction type for the transaction.

  • What's the difference between the ALWAYS_BEGIN, BEGIN_OR_JOIN, and INDIFFERENT transactional actions?

    ALWAYS_BEGIN always initiates a new transaction; BEGIN_OR_JOIN initiates a new transaction if there are no preceding transactions but joins an already set up transaction if one exists; and INDIFFERENT stays neutral, neither creating a transaction nor joining an existing one.

  • How do I configure an XA transaction in MuleSoft?

    You select XA as the transaction type in the Try scope settings and use the Bitronix Transaction Manager, added from the Global Elements section in Anypoint Studio. For the database connection config you tick the Use XA Transactions checkbox in its transactions section, and for the JMS connection config you scroll to the Connection Factory section, choose Edit inline for the factory configuration, and tick the Enable xa checkbox; note that XA will not work for a JMS connection when caching is activated, so you select No caching as the Caching Strategy. The components join the Try block's transaction by setting their transactional action to ALWAYS_JOIN.

  • Why does the XA transaction follow a 2-Phase-Commit protocol?

    The XA transaction uses a 2-Phase-Commit protocol because the first phase checks whether all the steps (the JDBC/JMS components) in a transaction completed successfully; if they all pass, the transaction manager commits and writes completion logs to a file ending with "tx-logs" in the .mule folder of your workspace directory, and if any component fails execution, the transaction manager rolls back the entire transaction.

Search

Loading search…