Transaction Management in Traditional Applications and Microservices: From Local Transactions to BASE and TCC
This article explains the evolution of transaction management from local and distributed (2PC/3PC) transactions in monolithic systems to the challenges in microservices, introduces the BASE theory, and details four microservice‑compatible consistency patterns—reliable event notification, max‑effort notification, business compensation, and TCC—along with their trade‑offs.
1. Traditional Transaction Management
1.1 Local Transactions
In monolithic applications a single RDBMS provides local transactions; the application opens a transaction, performs CRUD operations, and commits or rolls back, guaranteeing consistency within that transaction.
1.2 Distributed Transactions
1.2.1 Two‑Phase Commit (2PC)
When an application accesses multiple data sources, local transactions are insufficient, so a transaction manager (TM) coordinates a distributed transaction using the two‑phase commit protocol, which consists of a prepare phase and a commit phase.
1.2.2 Three‑Phase Commit (3PC)
To address blocking issues in 2PC, the three‑phase commit adds an extra phase, improving availability but still cannot guarantee consistency in all cases.
2. Transaction Management in Microservices
Distributed 2PC/3PC are unsuitable for microservices for three main reasons: (1) microservices communicate via RPC/HTTP and cannot be centrally managed by a TM; (2) heterogeneous data stores (e.g., NoSQL) may not support transactions; (3) long‑running global transactions cause lock contention and performance degradation.
Consequently, microservices adopt the BASE theory (Basically Available, Soft State, Eventual Consistency) proposed by eBay’s Dan Pritchett, which relaxes strong ACID guarantees in favor of eventual consistency.
Basically Available : the system remains core‑functional despite partial failures. Soft State : intermediate states are allowed and will converge later. Eventual Consistency : all replicas converge to the same state after some time.
3. Approaches to Achieve Data Consistency in Microservices
3.1 Reliable Event Notification
3.1.1 Synchronous Events
The primary service sends a result event (often via a message queue) to the secondary service synchronously; the business logic and message sending occur in the same transaction.
public void trans() {
try {
// 1. operate database
bool result = dao.update(data); // throws on failure
// 2. if DB succeeded, send message
if (result) {
mq.send(data); // throws on failure
}
} catch (Exception e) {
rollback(); // rollback on any exception
}
}Drawbacks: network or server failures after step 7 can cause the primary service to think the message failed while the secondary already processed it, leading to inconsistency; tight coupling between business and message services also reduces resilience.
3.1.2 Asynchronous Events
3.1.2.1 Local Event Service
The business service writes events to a local event table within the same transaction; a separate event service retries failed deliveries until successful, then removes the event record.
3.1.2.2 External Event Service
The event service is decoupled from the business service: the business records the event, commits/rolls back, then notifies the event service, which later attempts delivery and cleans up based on the final transaction outcome.
Both reliable modes must handle correct event delivery and idempotent consumption (ensuring 幂等性 ).
3.2 Max Effort Notification
The business service attempts to send a message a limited number of times after committing; if all attempts fail, the message is lost, and the upstream must provide a query interface for recovery. This mode offers low latency but weak consistency guarantees.
3.3 Business Compensation
When a downstream service fails, upstream services execute compensating actions (e.g., cancel a previously booked train ticket). Compensation is typically 不完全补偿 —the original record remains with a “canceled” flag, preserving auditability.
3.4 TCC (Try‑Confirm‑Cancel) Mode
TCC improves on pure compensation by providing a two‑phase protocol where the “try” phase reserves resources without performing real business logic; if all tries succeed, the “confirm” phase finalizes the operation, otherwise the “cancel” phase releases resources, achieving 完全补偿 .
// Service A (source bank)
try: update cmb_account set balance=balance-100, freeze=freeze+100 where acc_id=1 and balance>100;
confirm: update cmb_account set freeze=freeze-100 where acc_id=1;
cancel: update cmb_account set balance=balance+100, freeze=freeze-100 where acc_id=1;
// Service B (target bank)
try: update cgb_account set freeze=freeze+100 where acc_id=1;
confirm: update cgb_account set balance=balance+100, freeze=freeze-100 where acc_id=1;
cancel: update cgb_account set freeze=freeze-100 where acc_id=1;3.5 Summary
The table below compares the four common patterns (Maximum‑Effort, Reliable Event, Business Compensation, TCC) in terms of real‑time consistency, development cost, and whether the upstream service depends on the downstream result.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.