Some businesses require that a series of operations must be performed in full, not only in part. For example, a transfer operation:
--Transfer 100 yuan from the account with id = 1 to the account with id = 2 --Step 1: subtract 100 from the balance of account a with id = 1 UPDATE accounts SET balance = balance - 100 WHERE id = 1; --Step 2: add 100 to the balance of account B with id = 2 UPDATE accounts SET balance = balance + 100 WHERE id = 2;
These two SQL statements must all be executed, or, for some reason, if the first statement succeeds and the second statement fails, they must all be revoked.
This function of operating multiple statements as a whole is called database transaction. Database transactions can ensure that all operations within the scope of the transaction can succeed or fail. If the transaction fails, the effect will be the same as if these SQL were not executed, and there will be no changes to the database data.
More transaction introduction
If all operations involved in a transaction can be placed inside a service, the transaction operations of multiple operations as a whole can be easily realized by using the transaction related libraries in each language.
However, some services, such as generating orders, involve many operations, including inventory, coupons, gifts, account balances, etc. When the complexity of the system increases, if you want to implement all these operations in one service, the coupling will be too high and the maintenance cost will be very high.
For complex systems, the current popular microservice architecture is a very good solution. This architecture can split complex systems. After splitting, a large number of microservices are formed for independent development and maintenance.
More introduction to microservices
Although the service is split, the logic of the order itself requires multiple operations as a whole, either all successful or all failed, which brings new challenges. How to make the local transactions scattered in various microservices into a large transaction and ensure that they are taken as a whole is the problem that distributed transactions need to solve.
Distributed transaction simply means that a large operation is composed of different small operations. These small operations are distributed on different servers and belong to different applications. Distributed transaction needs to ensure that these small operations either succeed or fail. In essence, distributed transaction is to ensure the data consistency of different databases.
More about distributed transactions
The distributed transaction scheme includes:
- reliable information
Let’s take a look at the simplest Xa
Xa is a distributed transaction specification proposed by X / open organization. XA specification mainly defines the interface between (global) transaction manager (TM) and (local) resource manager (RM). Local databases such as MySQL play the role of RM in Xa
Xa is divided into two stages:
The first stage (prepare): that is, all participants RM are ready to execute transactions and lock the required resources. When participants are ready, report to TM that they are ready.
The second stage (commit / rollback): when the transaction manager (TM) confirms that all participants (RMS) are ready, it sends a commit command to all participants.
At present, the mainstream databases basically support XA transactions, including mysql, Oracle, sqlserver and Postgres
Let’s see how the local database supports XA:
Phase I preparation
XA start '4fPqCNTYeSG' UPDATE `user_account` SET `balance`=balance + 30,`update_time`='2021-06-09 11:50:42.438' WHERE user_id = '1' XA end '4fPqCNTYeSG' XA prepare '4fPqCNTYeSG' --When all participants have finished preparing, they will enter the second stage of submission xa commit '4fPqCNTYeSG'
After introducing so much, let’s practice and complete an XA transaction on a microservice to deepen the understanding of distributed transactions. Here, DTM is used as the manager of distributed transactions to run the demo of one of the XA transactions
git clone https://github.com/yedf/dtm.git cd dtm
cp conf.sample.yml conf.yml vi conf.yml
go run app/main.go xa
From the log, you can find the output of XA part, and finally successfully commit and complete the transaction
#Service 1 output XA start '4fPqCNTYeSG' UPDATE `user_account` SET `balance`=balance - 30,`update_time`='2021-06-09 11:50:42.438' WHERE user_id = '1' XA end '4fPqCNTYeSG' XA prepare '4fPqCNTYeSG' #Service 2 output XA start '4fPqCPijxyC' UPDATE `user_account` SET `balance`=balance + 30,`update_time`='2021-06-09 11:50:42.493' WHERE user_id = '2' XA end '4fPqCPijxyC' XA prepare '4fPqCPijxyC' #Service 1 output xa commit '4fPqCNTYeSG' #Service 2 output xa commit '4fPqCPijxyC'
The timing details of the whole interaction are as follows
At this point, a complete introduction to XA distributed transactions is completed.
In this short article, we briefly introduce transactions, distributed transactions, microservices and XA transactions. Interested students can continue to study distributed transactions through DTM.