Distributed Transaction Patterns and Implementation in Microservices

Local Transaction Fundamentals

Database transactions guarantee ACID properties: Atomicity, Consistency, Isolation, and Durability. In monolithic applications, a single connection handles multiple table operations, enabling straightforward rollback mechanisms.

Consider an e-commerce checkout flow:

  • Inventory Service: Deducts stock quantities
  • Order Service: Persists order records
  • Payment Service: Processes balance deductions

In a monolithic architecture, these operations share a single data base connection. When @Transactional is applied, any failure triggers a complete rollback across all operations.

Isolation Levels

Transaction isolation determines visibility of intermediate states between concurrent transactions:

  • READ UNCOMMITTED: Transactions read uncommitted changes from others, risking dirty reads.
  • READ COMMITTED: Only committed data is visible. Oracle and SQL Server default. Suffers from non-repeatable reads.
  • REPEATABLE READ: MySQL's default. Guarantees consistent reads within a transaction using MVCC, though phantom reads may occur (mitigated by next-key locking in InnoDB).
  • SERIALIZABLE: Complete isolation through locking. Eliminates concurrency anomalies but significantly reduces throughput.

Propagation Behaviors

Spring's transaction propagation defines how methods participate in existing transactions:

  • REQUIRED: Joins existing transaction or creates new one (default).
  • REQUIRES_NEW: Suspends current transaction and creates independent new transaction.
  • SUPPORTS: Joins existing transaction or executes non-transactionally.
  • NESTED: Executes within a nested transaction (savepoint-based).

The Proxy Trap

When methods invoke other transactional methods within the same class, transaction annotations are ignored because the call bypasses the Spring proxy.

Solution: Expose the proxy object:

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class TransactionConfig {
    // Enables AspectJ proxy exposure
}
@Service
public class OrderProcessor {
    
    @Transactional(timeout = 30)
    public void processOrder() {
        // Incorrect: this.b() bypasses proxy
        // Correct: Use AopContext to access proxy
        OrderProcessor proxy = (OrderProcessor) AopContext.currentProxy();
        proxy.calculateShipping();  // Respects REQUIRED propagation
        proxy.applyDiscount();      // Respects REQUIRES_NEW propagation
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void calculateShipping() { }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 20)
    public void applyDiscount() { }
}

Distributed Transaction Challenges

In microservices architectures, services maintain independent databases. Network latency, partial failures, and service timeouts create consistency challenges:

@Service
public class CheckoutService {
    
    @Transactional
    public OrderConfirmation checkout(Cart cart) {
        // 1. Create order locally
        Order order = createOrder(cart);
        saveOrder(order);
        
        // 2. Remote inventory lock
        InventoryResponse response = inventoryClient.reserveStock(order.getItems());
        
        if (response.isSuccess()) {
            // 3. Remote payment processing
            // If this fails, order rolls back but inventory remains locked
            paymentClient.charge(order.getTotal());
        }
        return new OrderConfirmation(order.getId());
    }
}

Failure Scenarios:

  • Inventory service succeeds but network timeout occurs: Order rolls back, inventory remains locked
  • Payment service fails after inventory deduction: Data inconsistency across services

Distributed Systems Theory

The CAP Theorem

Distributed systems face three competing constraints:

  • Consistency: All nodes observe identical data simultaneously
  • Availability: Every request receives a non-error response
  • Partition Tolerance: System operates despite network failures between nodes

Network partitions are inevitable in distributed systems. Therefore, systems must choose between:

  • CP: Consistency over availability (e.g., ZooKeeper, etcd)
  • AP: Availability over consistency (e.g., Cassandra, DynamoDB)

Consensus with Raft

Raft achieves consensus through leader election and log replication:

  1. Leader Election: Nodes transition between Follower, Candidate, and Leader states. If followers don't receive heartbeats within randomized election timeouts, they become candidates and request votes.
  2. Log Replication: The Leader accepts client requests and replicates entries to followers. Entries are committed once replicated by majority.

Raft ensures safety even during network partitions by requiring majority quorums.

BASE Properties

BASE provides a relaxed consistency model for high availability:

  • Basically Available: System remains operational during failures, potentially with degraded performance (e.g., degraded mode during peak traffic).
  • Soft State: State may change without external input due to eventual consistency mechanisms.
  • Eventual Consistency: Given sufficient time and no new updates, all replicas converge to identical values.

Transaction Coordination Patterns

Two-Phase Commit (2PC)

XA protocol implements 2PC across participating databases:

  1. Prepare Phase: Coordinator asks participants to vote on commit feasibility
  2. Commit Phase: If all vote yes, coordinator issues commit; otherwise, rollback

Limitations:

  • Synchronous blocking reduces throughput
  • Coordinator single point of failure
  • Limited NoSQL support
  • MySQL's XA implementation lacks prepare-phase logging, risking inconsistency during failover

Try-Confirmm-Cancel (TCC)

TCC implements compensation-based transactions:

  • Try: Reserve resources (validate business rules, lock inventory)
  • Confirm: Commit reserved resources (deduct inventory, process payment)
  • Cancel: Release reserved resources (unlock inventory, refund payment)

Each service exposes three operations, allowing the coordinator to drive the transaction to completion.

Saga Pattern

Long-running transactions are split into local transactions with compensating actions:

  • Forward Operation: Business logic execution
  • Compensating Operation: Undo logic for rollback scenarios

If step 3 fails, execute compensating actions for steps 2 and 1.

Reliable Messaging

Asynchronous consistency through message brokers:

Producer Side:

  • Implement at-least-once delivery with message persistence
  • Use outbox pattern: Write to business table and message table atomically
  • Scheduled job retries failed messages

Consumer Side:

  • Manual acknowledgment mode prevents message loss
  • Idempotent consumers handle duplicate deliveries
  • Business status checks prevent double-processing

Seata Implementation

Seata (Simple Extensible Autonomous Transaction Architecture) provides distributed transaction coordination:

  • TC (Transaction Coordinator): Manages global transaction lifecycle and branch registration
  • TM (Transaction Manager): Defines global transaction boundaries (begin, commit, rollback)
  • RM (Resource Manager): Manages branch transactions and reports status to TC

Integration Setup

1. Database Preparation Create undo_log table in each service database:

CREATE TABLE IF NOT EXISTS `undo_log` (
    `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
    `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context` VARCHAR(128) NOT NULL COMMENT 'serialization context',
    `rollback_info` LONGBLOB NOT NULL COMMENT 'undo info',
    `log_status` INT(11) NOT NULL COMMENT '0: normal, 1: defense',
    `log_created` DATETIME(6) NOT NULL,
    `log_modified` DATETIME(6) NOT NULL,
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`),
    INDEX `ix_log_created` (`log_created`)
) ENGINE = InnoDB COMMENT ='AT transaction undo table';

2. Dependency Configuration

<dependency>
    <groupId>org.apache.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.7.0</version>
</dependency>

3. DataSource Proxy

@Configuration
public class SeataDataSourceConfig {
    
    @Bean
    @Primary
    public DataSource dataSource(DataSourceProperties props) {
        HikariDataSource hikari = props
            .initializeDataSourceBuilder()
            .type(HikariDataSource.class)
            .build();
        
        if (StringUtils.hasText(props.getName())) {
            hikari.setPoolName(props.getName());
        }
        // Wrap with Seata proxy for distributed transaction tracking
        return new DataSourceProxy(hikari);
    }
}

4. Service Configuration

Configure service group mappings in application.yml:

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: my-service-group
  service:
    vgroup-mapping:
      my-service-group: default
  registry:
    type: nacos
    nacos:
      server-addr: localhost:8848

5. Transaction Annotations

Mark entry points with @GlobalTransactional and local services with @Transactional:

@Service
public class OrderOrchestrator {
    
    @GlobalTransactional(name = 'checkout-tx', rollbackFor = Exception.class)
    public OrderResult processCheckout(CheckoutRequest request) {
        // 1. Create order
        OrderEntity order = orderService.createOrder(request);
        
        // 2. Deduct inventory via RPC
        inventoryService.deduct(order.getSkuList());
        
        // 3. Process payment via RPC
        // Failure here triggers global rollback of inventory and order
        paymentService.charge(order.getPaymentInfo());
        
        return new OrderResult(order.getId());
    }
}

@Service
public class InventoryManager {
    
    @Transactional
    public void deduct(List<SkuItem> items) {
        // Local transaction participates in global coordination
        items.forEach(item -> 
            skuMapper.decreaseStock(item.getSkuId(), item.getQuantity())
        );
    }
}

The AT (Auto-transaction) mode automatically generates reverse SQL from undo logs, enabling seamless rollback without manual compensation logic.

Tags: Distributed Transactions microservices Seata CAP Theorem Spring Cloud

Posted on Sun, 19 Jul 2026 16:53:36 +0000 by TANK