Designing a Robust Transaction System: From Domain Modeling to Distributed Consistency
This article explores how to build a reliable, scalable transaction module for e‑commerce and finance, covering business requirement analysis, domain modeling, state‑machine design, layered microservice architecture, order creation and payment flows, idempotency, anti‑oversell mechanisms, performance tuning, monitoring, and evolution strategies.
Phase 1: Business Requirement Analysis & Domain Modeling
The transaction module is the heart of any e‑commerce, finance, or O2O system; its design directly impacts stability, consistency, user experience, and scalability.
1️⃣ Core Business Process
A typical order flow includes placing an order, payment, shipping, receipt, and completion. The diagram below illustrates the steps.
2️⃣ Key Business Entities
Order : core entity containing order number, user ID, amount, status, address, etc.
OrderItem : one‑to‑many relationship with Order, records SKU, quantity, unit price.
PaymentRecord : records payment method, amount, and status.
RefundOrder : manages refund/return processes, independent of the main order.
3️⃣ State Machine Design (Core of the Core)
Order status is the soul of the transaction system.
Main States
Pending Payment → Paid / Awaiting Shipment → Shipped / Awaiting Receipt → CompletedReverse States
Pending Payment → Cancelled (manual/timeout)
Paid / Completed → Refund In Progress / RefundedState Transition Diagram
+------------+
| Pending |<
+------------+ |
| (payment success) |
v |
+------------+ (cancel/timeout) |
| Paid |------------------+
+------------+
| (ship)
v
+------------+
| Shipped |
+------------+
| (confirm receipt / auto‑receive)
v
+------------+
| Completed |
+------------+Phase 2: System Architecture & Core Modules
The transaction system should adopt a layered architecture combined with microservice decomposition to achieve high cohesion and low coupling.
System Architecture Diagram
Core Module Responsibilities
Order Service : manages order lifecycle; key APIs: createOrder(), cancelOrder(), updateStatus() Payment Service : integrates external payment channels; APIs: initiatePay(), payCallback(), refund() Product Service : handles inventory and product details; APIs: lockStock(), deductStock(), rollbackStock() Coupon Service : calculates and verifies discounts; APIs: calculateDiscount(),
verifyCoupon()Phase 3: Core Process & Key Technical Implementation
1. Order Creation – “How to Safely Create a Transaction”
Recommended eventual‑consistency solution uses asynchronous compensation + delayed messages instead of distributed XA transactions.
Process Steps
Pre‑validation : verify user, stock, and price consistency.
Generate Order ID : use Snowflake algorithm or segment service (Leaf/TinyID).
Lock Stock (atomic update) :
UPDATE stock SET locked_stock = locked_stock + ? WHERE sku_id = ? AND stock >= locked_stock + ?;Insert Order Record : status set to “Pending Payment”.
Delayed Compensation : if not paid within 10 minutes, send an MQ message to release stock.
mqTemplate.convertAndSend("order.delay.exchange", "order.cancel", orderId, msg -> {
msg.getMessageProperties().setExpiration("600000"); // 10 minutes
return msg;
});2. Payment Callback – “Ensuring Idempotency and Reliability”
Core Flow
Receive callback from WeChat/Alipay.
Idempotency check:
if (paymentRecordService.isProcessed(thirdTradeNo)) {
return SUCCESS;
}Within a transaction, update payment record to “Paid” and order status to “Paid”.
Publish asynchronous event order.paid for downstream services (stock, points, marketing).
Return success to the third‑party; otherwise allow retry.
3. Refund & After‑Sale Process
Create an independent t_refund_order table linked one‑to‑one with the order.
Refund status flows independently but triggers related events via messaging.
4. Duplicate Submission & Idempotency Design
Scenario: User repeatedly clicks “Place Order” – Solution: generate a one‑time token before order submission.
Scenario: Concurrent orders – Solution: Redis distributed lock on user_id + sku_id.
Scenario: Message duplicate consumption – Solution: idempotent consumption table recording message_id.
if (!redisLock.tryLock(userId + skuId)) {
throw new BizException("Duplicate order");
}5. Over‑sell Prevention
Database layer: optimistic lock using a version field.
Cache layer: Redis atomic decrement; failure indicates insufficient stock.
Message layer: timeout rollback to release stock for unpaid orders.
Phase 4: Non‑Functional Design
High Availability & Scalability
Stateless services enable horizontal scaling.
Sharding by user ID or order number.
Read‑write separation: master for writes, slaves for reads.
Performance Optimization & Caching
Redis cache for hot data.
Guava local cache for dictionary information.
Static product detail pages.
Data Consistency Guarantees
Rigid transactions: intra‑service @Transactional.
Flexible transactions: eventual consistency via reliable messages and compensation.
Resilience & Monitoring
Circuit breaking with Sentinel/Hystrix.
Trace ID per transaction for link tracing.
Metrics alerts for QPS, latency, and error rate.
Phase 5: Architecture Evolution & Optimization
Roadmap
Plug‑in Architecture
Discount calculation, freight calculation, and similar modules can be implemented as rule engines or plug‑ins for dynamic configuration.
Internationalization
Support multiple currencies, languages, and time zones in the order model.
Heterogeneous Data Stores
Write to MySQL, read from Elasticsearch to decouple performance bottlenecks.
Phase 6: Transaction Consistency Model
Application layer: front‑end displays consistent data via status polling and aggregation.
System layer: services converge to a final state using MQ reliable messages and compensation.
Data layer: intra‑service consistency via local transactions.
Phase 7: Security & Compliance
Signature verification for payment parameters to prevent tampering.
Sensitive data masking and encryption (phone numbers, card numbers).
Audit logs recording all transaction actions.
PCI DSS compliance for payment services.
Phase 8: Database Table Design Example
CREATE TABLE t_order (
id BIGINT PRIMARY KEY,
order_no VARCHAR(64) UNIQUE NOT NULL,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10,2),
status VARCHAR(20),
create_time DATETIME,
update_time DATETIME
);
CREATE TABLE t_payment_record (
id BIGINT PRIMARY KEY,
order_no VARCHAR(64),
payment_no VARCHAR(64),
pay_channel VARCHAR(20),
pay_amount DECIMAL(10,2),
pay_status VARCHAR(20),
notify_time DATETIME
);Conclusion
Designing a robust transaction module is about balancing business complexity with system complexity, employing decomposition, clear domain models, state machines, eventual consistency, idempotent payment handling, delayed compensation, and comprehensive monitoring, circuit breaking, and logging.
Ray's Galactic Tech
Practice together, never alone. We cover programming languages, development tools, learning methods, and pitfall notes. We simplify complex topics, guiding you from beginner to advanced. Weekly practical content—let's grow together!
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.
