[SeataAT-2]数据源代理/资源管理器/数据库连接代理/StatementProxy和PreparedStamentProxy

81 阅读4分钟

Seata数据源代理:分布式事务的"物流监控系统"

引言:快递公司的智能升级

想象一家普通快递公司突然获得超能力:每个包裹都自带监控摄像头,仓库配备智能分拣系统,快递员配备轨迹记录仪。这正是Seata数据源代理要完成的工作——让普通数据库连接获得"事务监控超能力"。让我们拆解这套"物流监控系统"的技术实现。


一、数据源代理类:快递公司的安检门

1.1 设计模式:装饰器模式

DataSourceProxy如同快递站入口的智能安检门,对原始数据源(普通快递车)进行增强:

public class DataSourceProxy extends AbstractDataSourceProxy {
    private final DataSource targetDataSource; // 被装饰的原始数据源
    
    public ConnectionProxy getConnection() throws SQLException {
        // 创建具备监控能力的连接
        return new ConnectionProxy(targetDataSource.getConnection(), 
                                  resourceManager, defaultAutoCommit);
    }
}

就像给每辆快递车安装GPS定位器,在保持原有运输能力的基础上增加轨迹追踪功能。

1.2 核心能力

  • 连接包装:将原生Connection升级为ConnectionProxy
  • 资源注册:自动向TransactionManager注册分支事务
  • SQL解析:识别业务SQL中的"危险品"(更新操作)

二、资源管理器:物流调度中心

2.1 ResourceManager设计

public interface ResourceManager {
    void registerResource(Resource resource); // 注册分支事务资源
    void commit(String xid, long branchId);   // 提交指令下发
    void rollback(String xid, long branchId); // 回滚指令处理
}

这就像物流调度中心的控制台,管理着所有分支仓库(数据库资源)的状态。

2.2 分支事务管理

当新的快递分站(数据库连接)加入时:

// DefaultResourceManager.java
public void registerResource(Resource resource) {
    if (resource instanceof DataSourceProxy) {
        dataSourceManager.registerResource((DataSourceProxy)resource);
    }
    // 其他资源类型处理...
}

每个分站都会被记录在调度中心的登记簿中,确保异常时能快速定位问题包裹。


三、数据库连接代理:快递员的智能手环

3.1 ConnectionProxy结构

public class ConnectionProxy implements Connection {
    private final Connection originalConnection; // 原生连接
    private final DataSourceProxy dataSourceProxy;
    
    public void commit() throws SQLException {
        if (isInGlobalTransaction()) { // 全局事务中
            reportToTransactionManager(); // 向调度中心汇报
        } else {
            originalConnection.commit(); // 本地直接提交
        }
    }
}

就像快递员的手环,在普通配送(本地事务)时正常运作,在跨城运输(全局事务)时自动开启轨迹记录。

3.2 自动提交管理

public void setAutoCommit(boolean autoCommit) {
    if (autoCommit && isInGlobalTransaction()) {
        // 全局事务中禁止自动提交
        throw new SQLException("Seata禁止在全局事务中启用自动提交");
    }
    originalConnection.setAutoCommit(autoCommit);
}

这相当于强制要求跨城运输必须使用指定路线,避免快递员私自改变配送路线。


四、Statement代理:包裹面单扫描仪

4.1 StatementProxy拦截机制

public class StatementProxy extends AbstractStatementProxy 
    implements Statement {
    
    public ResultSet executeQuery(String sql) throws SQLException {
        // 1. SQL解析(面单信息识别)
        Executor executor = ExecutorFactory.getExecutor(sql);
        
        // 2. 前置处理(拍摄发货前照片)
        TableRecords beforeImage = executor.beforeImage();
        
        // 3. 执行原始操作(实际运输)
        ResultSet rs = originalStatement.executeQuery(sql);
        
        // 4. 后置处理(拍摄发货后照片)
        TableRecords afterImage = executor.afterImage(beforeImage);
        
        // 5. 保存快照到undo_log(面单存档)
        UndoLogManager.saveUndoLog(...);
        
        return rs;
    }
}

这个过程就像智能面单扫描仪,在包裹出入库时自动拍摄对比照片,确保异常时可追溯。

4.2 PreparedStatementProxy增强

public class PreparedStatementProxy extends AbstractPreparedStatementProxy {
    public int executeUpdate() throws SQLException {
        // 参数化SQL解析(识别危险品类型)
        SQLRecognizer recognizer = SQLVisitorFactory.get(sql);
        
        // 生成唯一包裹ID(行锁键)
        List<String> lockKeys = LockKeyBuilder.buildLockKey(recognizer, parameters);
        
        // 向TC申请锁(运输许可证)
        boolean lockResult = DataSourceManager.lock(lockKeys);
        
        // 后续处理与StatementProxy类似...
    }
}

这种设计就像对特殊包裹(参数化SQL)进行深度安检,确保不会与其他运输任务冲突。


五、技术全景:物流监控体系

graph LR
    A[应用代码] --> B(DataSourceProxy)
    B --> C[ConnectionProxy]
    C --> D[StatementProxy]
    C --> E[PreparedStatementProxy]
    D --> F{SQL执行拦截}
    E --> F
    F --> G[UndoLog记录]
    F --> H[全局锁管理]
    G --> I[事务回滚]
    H --> J[数据一致性]
    
    classDef tech fill:#f9f,stroke:#333;
    class B,C,D,E tech;

六、设计启示:监控与透明的平衡

  1. 代理模式的精准应用:如同给快递车加装监控但不影响运输能力
  2. 责任链模式的灵活运用:每个环节只处理特定类型"包裹"(SQL类型)
  3. 模板方法模式的巧妙实现:在Statement执行流程中固化监控逻辑

源码启示:Seata 1.5.2版本中,executor模块的AbstractDMLBaseExecutor定义了SQL执行的标准流程,如同物流公司制定的标准操作手册。


结语:透明化改造的艺术

Seata的数据源代理体系,就像给传统物流系统植入神经感知网络。通过层层代理的"传感器"(Proxy对象),在不改变原有运输流程(业务代码)的前提下,实现了全链路监控。这种设计哲学告诉我们:优秀的中间件应该像空气一样——感受不到存在,但时刻提供保护。