DaaS / Products / Distributed Transaction via RocketMQ and OceanBase

Distributed Transaction via RocketMQ and OceanBase

An e-commerce or financial system uses RocketMQ transactional messages to coordinate order placement with OceanBase distributed transactions — a half-message is sent, the local OceanBase transaction (e.g., deduct inventory, create order) executes, then the message is committed or rolled back based on the DB outcome. Downstream services consume the committed messages and apply their own OceanBase transactions, achieving reliable end-to-end eventual consistency.

Products involved

Scenario

Use this pattern when building e-commerce or financial workflows that require strong local consistency paired with reliable cross-service eventual consistency. It decouples order creation from downstream processes (e.g., payment, fulfillment) while guaranteeing that no message is delivered without a corresponding committed database state.

Integration steps

  1. Initialize Transactional Producer: Configure TransactionMQProducer with setNamesrvAddr("mq-broker:9876") and inject a ScheduledExecutorService via setTransactionCheckExecutor() for background half-message verification.
  2. Implement TransactionListener: Create a class implementing executeLocalTransaction() and checkLocalTransaction(). In executeLocalTransaction(), open an OceanBase JDBC connection, call conn.setAutoCommit(false), run inventory deduction and order insertion, then return LocalTransactionState.COMMIT_MESSAGE or ROLLBACK_MESSAGE.
  3. Send Half-Message: Invoke producer.sendMessageInTransaction(msg, arg). The broker persists the half-message to RMQ_SYS_TRANS_HALF_TOPIC and awaits the local DB outcome.
  4. Resolve In-Doubt States: If the broker callback triggers checkLocalTransaction(), query the OceanBase order table using msg.getKeys() as the primary key. Return the persisted state to prevent message loss during network partitions.
  5. Configure Downstream Consumer: Initialize DefaultMQPushConsumer in CLUSTERING mode, call subscribe("ORDER_TOPIC", "*"), and register a MessageListenerConcurrently. Tune consumeThreadMin/Max for parallel throughput.
  6. Process & Commit in Consumer: In consumeMessage(), parse the payload, start a new OceanBase transaction (setAutoCommit(false)), apply downstream logic, and call conn.commit(). Return ConsumeConcurrentlyStatus.CONSUME_SUCCESS or RECONSUME_LATER on failure.

Architecture

The producer first sends a half-message to RocketMQ, executes a local OceanBase ACID transaction, and commits/rolls back the message based on the DB result. Once committed, the broker routes the message to the consumer group. Consumers pull messages, apply their own OceanBase transactions, and acknowledge success, achieving end-to-end eventual consistency without distributed 2PC overhead.

Prerequisites

Common pitfalls

Typical questions