一、分布式事务的那些事儿

说到分布式事务,很多开发者都会头疼。想象一下,你在网上购物,付款成功后订单却没生成,或者订单生成了但没扣款,这种场景是不是很崩溃?这就是典型的分布式事务问题。OceanBase作为一款分布式数据库,自然也绕不开这个坎儿。

分布式事务的核心难题是“数据一致性”。比如,A系统扣款成功,B系统生成订单失败,这时候钱扣了但货没买到,用户肯定要炸锅。OceanBase的解决方案是“两阶段提交”(2PC),但光知道2PC还不够,我们得深入看看它怎么在实际场景中落地。

二、OceanBase的两阶段提交实战

OceanBase的两阶段提交分为准备阶段和提交阶段。下面用Java代码模拟一个跨库转账的场景(假设有两个库:账户库和交易库):

// 技术栈:Java + OceanBase JDBC
public class TransferService {
    @Transactional
    public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
        // 第一阶段:准备
        jdbcTemplate.update("UPDATE account SET balance = balance - ? WHERE id = ?", amount, fromAccount);
        jdbcTemplate.update("INSERT INTO transaction_log(from_account, to_account, amount) VALUES (?, ?, ?)", 
                           fromAccount, toAccount, amount);
        
        // 第二阶段:提交(由@Transactional自动触发)
        // 如果任何一步失败,整个事务回滚
    }
}

代码注释:

  1. @Transactional注解让Spring管理事务边界
  2. 先扣减余额,再记录交易日志,两步操作要么全成功,要么全回滚
  3. OceanBase的JDBC驱动会自动适配分布式事务协议

但实际生产环境会更复杂。比如网络闪断导致第一阶段成功,第二阶段超时,这时候就需要“事务恢复”机制。

三、常见坑与填坑指南

1. 超时问题

OceanBase默认的事务超时时间是10秒。如果事务执行时间过长,可能会这样:

-- 设置会话级事务超时(单位:微秒)
SET ob_trx_timeout = 20000000; -- 20秒

注意: 不要盲目调大超时时间,应该先优化慢SQL。

2. 死锁检测

分布式死锁比单机更复杂。OceanBase通过全局时间戳检测死锁,但有时需要手动干预:

// 手动加锁顺序控制
public void safeTransfer(String smallId, String bigId) {
    if (smallId.compareTo(bigId) > 0) {
        String temp = smallId;
        smallId = bigId;
        bigId = temp;
    }
    // 总是先锁ID小的记录
    lock(smallId);
    lock(bigId);
}

3. 大事务拆分

OceanBase对单事务的大小有限制(默认100MB日志量),大事务要拆解:

// 分批处理
for (int i = 0; i < total; i += BATCH_SIZE) {
    jdbcTemplate.batchUpdate("INSERT INTO large_table VALUES (?)", 
        new BatchPreparedStatementSetter() {
            // 每批100条
        });
}

四、高阶玩法:最终一致性

对于对实时性要求不高的场景,可以用“消息队列+重试”实现最终一致性。以用户注册为例:

// 技术栈:Java + RocketMQ
public void register(User user) {
    // 1. 先落库
    userDao.insert(user);
    
    // 2. 发消息(可能失败)
    rocketMQTemplate.send("user-register-topic", 
        new Message(user.getId(), "REGISTER"));
    
    // 3. 启动补偿任务(定时检查未处理的消息)
}

关键点:

  • 消息表需要和业务表在同一个本地事务中
  • 补偿任务要有幂等设计

五、选型与总结

适用场景:

  • 金融交易(强一致性)
  • 物流状态(最终一致性)
  • 跨业务系统集成

优缺点:

优点:

  • 原生支持分布式ACID
  • 自动故障恢复
  • 兼容MySQL协议

缺点:

  • 性能损耗比单机事务高约20%
  • 运维复杂度较高

注意事项:

  1. 避免跨机房事务(网络延迟会飙升)
  2. 监控v$ob_transaction视图
  3. 压测时重点关注事务冲突率

最后说句大实话:没有银弹。分布式事务的方案选型,本质上是在一致性、可用性和开发成本之间找平衡点。OceanBase给了我们不错的工具,但用得好不好,还得看架构师的设计功力。