Loading...
Loading...
Seata distributed transaction skill. Covers a decision tree for selecting among the AT/TCC/SAGA/XA modes, the mandatory undo_log table for AT mode, useTCCFence in TCC mode for handling idempotency, suspension, and empty rollback, SAGA state machines for long-running workflows, global transaction timeout configuration (@GlobalTransactional timeoutMills), and read isolation enhancement (@GlobalLock + FOR UPDATE). Corrects common LLM mistakes: not knowing which of AT/TCC/SAGA to choose, not creating the undo_log table, making TCC Confirm non-idempotent, and ignoring watchdog handling.
npx skill4agent add full-stack-skills/java-skills seata-patternsNeed a distributed transaction?
├── Need strong consistency (financial core) → XA mode (poor performance)
├── Eventual consistency is sufficient
│ ├── Transaction execution time > 10 seconds → SAGA mode (state machine)
│ ├── High concurrency + willing to implement Confirm/Cancel → TCC mode
│ └── 80% of scenarios (default recommendation) → AT mode (zero intrusion)| # | Error | Correct Approach |
|---|---|---|
| 1 | Not knowing that AT mode requires an undo_log table | Create an |
| 2 | Using a non-ACID database in AT mode | AT relies on local transactions and requires MySQL/PostgreSQL/Oracle |
| 3 | Not configuring the global transaction timeout (the default 60s may be insufficient) | Configure |
| 4 | Not making TCC-mode Confirm idempotent | Confirm must be idempotent (globally unique ID + deduplication index) |
| 5 | Not handling empty rollback in TCC mode | Use |
| 6 | Not handling read isolation (reading data not yet committed by the global transaction) | Add |
| 7 | Assuming that SAGA mode automatically rolls back | SAGA requires manually implemented compensation logic |
| 8 | Excessive global transaction duration (lock contention) | Set a reasonable timeout (15–30 seconds recommended) |
-- ✅ Every business database must have an undo_log table
CREATE TABLE IF NOT EXISTS undo_log (
id BIGINT NOT NULL AUTO_INCREMENT,
branch_id BIGINT NOT NULL,
xid VARCHAR(128) NOT NULL,
context VARCHAR(128) NOT NULL,
rollback_info LONGBLOB NOT NULL,
log_status INT NOT NULL,
log_created DATETIME NOT NULL,
log_modified DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY ux_undo_log (xid, branch_id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;// ✅ AT mode: annotations only, with no business-logic intrusion
@Service
public class OrderService {
@GlobalTransactional(timeoutMills = 300000, rollbackFor = Exception.class)
public void createOrder(OrderDTO dto) {
orderService.create(dto); // Remote service A (local transaction)
inventoryService.deduct(dto); // Remote service B (local transaction)
accountService.debit(dto); // Remote service C (local transaction)
// If any step fails → all are automatically rolled back (based on undo_log)
}
}@LocalTCC
public interface AccountTccAction {
@TwoPhaseBusinessAction(
name = "accountTcc",
commitMethod = "confirm",
rollbackMethod = "cancel",
useTCCFence = true // ← Seata 1.5.1+ automatically handles idempotency, suspension, and empty rollback
)
boolean prepare(BusinessActionContext ctx,
@BusinessActionContextParameter(paramName = "accountDTO") AccountDTO dto);
// ✅ Confirm must be idempotent (can be executed repeatedly without changing the result)
boolean confirm(BusinessActionContext ctx);
// ✅ Cancel must be an idempotent compensation (it may arrive before Try executes = empty rollback)
boolean cancel(BusinessActionContext ctx);
}// SAGA uses a state machine engine and orchestrates long-running transactions through JSON configuration
// Each step has a forward action (serviceMethod) and a compensation action (compensateMethod)
// Applicable scenarios: order fulfillment, approval workflows, and logistics tracking
// Compensation order must be executed in strict reverse order
// Compensation operations must be idempotent and retryable@GlobalLock
@Transactional
public Order getOrder(Long orderId) {
// ✅ FOR UPDATE + @GlobalLock prevents dirty reads in AT mode
return orderMapper.selectForUpdate(orderId);
}<select id="selectForUpdate" resultMap="BaseResultMap">
SELECT * FROM orders WHERE id = #{id} FOR UPDATE
</select>