分布式事务是处理跨多个服务或数据库的数据一致性的关键技术。下面我将全面解析分布式事务的应用场景、主流解决方案及其实现原理。
场景类型 | 具体案例 | 一致性要求 |
---|---|---|
跨服务转账 | 银行A向银行B转账 | 必须同时成功或失败 |
订单支付 | 创建订单+扣减库存+支付 | 多系统状态必须一致 |
物流跟踪 | 订单状态更新+物流记录创建 | 数据必须同步变更 |
会员积分 | 购物获得积分+等级提升 | 积分与等级需原子更新 |
分布式文件存储 | 文件上传到多个数据中心 | 所有节点需同步成功 |
实现原理:
代码示例:
// 伪代码示例
public boolean twoPhaseCommit(List<Participant> participants) {
// 阶段一:准备
boolean allPrepared = participants.stream()
.allMatch(p -> p.prepare());
// 阶段二:提交或回滚
if(allPrepared) {
participants.forEach(p -> p.commit());
return true;
} else {
participants.forEach(p -> p.rollback());
return false;
}
}
优缺点:
改进点:
阶段流程:
CanCommit → PreCommit → DoCommit
模式:
代码示例:
public class OrderTccService {
@Transactional
public void tryCreateOrder(Order order) {
// 冻结库存而非直接扣减
inventoryService.freeze(order.getItems());
// 创建临时订单
order.setStatus("TRYING");
orderRepository.save(order);
}
@Transactional
public void confirmCreateOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 确认正式订单
order.setStatus("CONFIRMED");
// 实际扣减库存
inventoryService.reduce(order.getItems());
}
@Transactional
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 取消订单
order.setStatus("CANCELLED");
// 释放冻结库存
inventoryService.unfreeze(order.getItems());
}
}
适用场景:
实现方式:
示例流程:
订单服务(创建) → 支付服务(扣款) → 库存服务(扣减)
↓ 失败时触发反向操作
订单服务(取消) ← 支付服务(退款) ← 库存服务(回滚)
代码实现:
public class OrderSaga {
public void createOrder(Order order) {
try {
// 1. 创建订单
orderService.create(order);
// 2. 支付
paymentService.charge(order);
// 3. 扣库存
inventoryService.reduce(order.getItems());
} catch (Exception e) {
// 触发补偿流程
compensate(order);
}
}
private void compensate(Order order) {
// 反向执行补偿操作
inventoryService.compensateReduce(order.getItems());
paymentService.refund(order);
orderService.cancel(order);
}
}
实现步骤:
架构示例:
CREATE TABLE transaction_messages (
id BIGINT PRIMARY KEY,
biz_id VARCHAR(64),
payload TEXT,
status VARCHAR(20),
created_time DATETIME,
retry_count INT
);
@Service
public class OrderService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void createOrder(Order order) {
// 1. 保存订单
orderRepository.save(order);
// 2. 写入消息表(同库事务)
String sql = "INSERT INTO transaction_messages VALUES (?,?,?,?,?,?)";
jdbcTemplate.update(sql,
generateId(),
order.getId(),
JsonUtils.toJson(order),
"PENDING",
new Date(),
0);
}
}
// 独立的消息发送服务
@Scheduled(fixedRate = 5000)
public void processPendingMessages() {
List<Message> messages = jdbcTemplate.query(
"SELECT * FROM transaction_messages WHERE status='PENDING' LIMIT 100",
new MessageRowMapper());
messages.forEach(msg -> {
try {
// 发送到MQ
rocketMQTemplate.send(msg);
// 更新状态
jdbcTemplate.update(
"UPDATE transaction_messages SET status='SENT' WHERE id=?",
msg.getId());
} catch (Exception e) {
// 更新重试次数
jdbcTemplate.update(
"UPDATE transaction_messages SET retry_count=retry_count+1 WHERE id=?",
msg.getId());
}
});
}
支持模式:
架构组成:
配置示例:
# application.yml
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
grouplist:
default: 127.0.0.1:8091
RocketMQ事务消息流程:
public class OrderProducer {
public void createOrder(Order order) {
// 构建消息
Message msg = new Message(
"ORDER_TOPIC",
"CREATE",
order.getId().toString(),
JsonUtils.toJson(order).getBytes());
// 发送事务消息
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(
"order-producer-group",
msg,
order);
// 处理发送结果
if(result.getLocalTransactionState() == LocalTransactionState.COMMIT_MESSAGE) {
log.info("事务提交成功");
} else {
log.error("事务提交失败");
}
}
}
// 事务监听器
@RocketMQTransactionListener
public class OrderTransactionListener implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
Order order = (Order) arg;
orderService.save(order);
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK;
}
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
String orderId = msg.getKeys();
boolean exists = orderService.exists(orderId);
return exists ? RocketMQLocalTransactionState.COMMIT
: RocketMQLocalTransactionState.ROLLBACK;
}
}
方案 | 一致性 | 性能 | 复杂度 | 适用场景 | 代表实现 |
---|---|---|---|---|---|
2PC | 强一致 | 低 | 中 | 传统银行系统 | XA协议 |
TCC | 最终一致 | 高 | 高 | 电商交易 | Seata |
Saga | 最终一致 | 高 | 高 | 长流程业务 | ServiceComb |
本地消息表 | 最终一致 | 中 | 中 | 异步通知 | 自实现 |
事务消息 | 最终一致 | 高 | 中 | 消息驱动 | RocketMQ |
是否需要强一致性?
├─ 是 → 考虑2PC/3PC(适合低频关键业务)
└─ 否 → 选择最终一致性方案
├─ 业务可补偿 → TCC/Saga
├─ 异步通知 → 本地消息表
└─ 消息驱动 → 事务消息
超时处理:设置合理的超时时间
// Seata全局事务超时设置
@GlobalTransactional(timeoutMills = 30000)
public void businessMethod() {
// ...
}
空回滚问题:记录Try操作状态
CREATE TABLE tcc_record (
xid VARCHAR(128) PRIMARY KEY,
status TINYINT, -- 1:try, 2:confirm, 3:cancel
created_time DATETIME
);
悬挂问题:检查Confirm/Cancel前Try是否完成
性能瓶颈:避免热点数据,如:
// 错误做法 - 全局账户表锁
@Transactional
public void transfer(Account from, Account to) {
// ...
}
// 正确做法 - 账户分片
@Transactional
public void transfer(Long fromId, Long toId) {
Account from = accountShardService.getAccount(fromId);
Account to = accountShardService.getAccount(toId);
// ...
}
# 补偿策略配置示例
compensable:
max-retries: 3
backoff:
initial-interval: 1000
multiplier: 2
分布式事务的选择和实施需要根据具体业务场景、数据一致性要求和系统架构综合考量。随着云原生技术的发展,分布式事务解决方案也在不断演进,开发者应当持续关注新技术动态,同时掌握经典模式的适用场景和实现原理。