侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计支持多数据源动态切换和事务管理的数据库访问框架

2025-12-9 / 0 评论 / 4 阅读

题目

设计支持多数据源动态切换和事务管理的数据库访问框架

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

抽象工厂模式,策略模式,事务管理,动态代理,连接池管理

快速回答

核心实现要点:

  • 使用抽象工厂模式创建不同数据源的数据库连接
  • 通过策略模式实现运行时数据源切换逻辑
  • 结合ThreadLocal保证线程级数据源隔离
  • 采用Spring事务管理扩展点实现事务同步
  • 利用动态代理实现方法级数据源路由
  • 通过连接池包装器防止连接泄漏
## 解析

问题背景

在大型分布式系统中,需要根据业务场景动态切换主/从数据库、分库分表或不同厂商数据库。难点在于:1)运行时无缝切换 2)事务一致性 3)资源安全管理。

核心设计

1. 模式组合架构

// 抽象工厂模式 - 数据源创建
public abstract class DataSourceFactory {
    public abstract DataSource createDataSource(Config config);
}

// 策略模式 - 数据源选择
public interface RoutingStrategy {
    String determineDataSource(Method method, Object[] args);
}

2. 动态数据源路由

// 动态代理实现路由
public class DataSourceProxy implements InvocationHandler {
    private Object target;
    private RoutingStrategy strategy;

    public Object invoke(Object proxy, Method method, Object[] args) {
        String dsKey = strategy.determineDataSource(method, args);
        DataSourceContextHolder.set(dsKey);  // 使用ThreadLocal绑定
        try {
            return method.invoke(target, args);
        } finally {
            DataSourceContextHolder.clear();
        }
    }
}

3. 事务同步关键代码

// 继承AbstractPlatformTransactionManager
public class MultiDataSourceTransactionManager extends AbstractPlatformTransactionManager {

    protected Object doGetTransaction() {
        // 获取当前线程绑定的真实连接
        Connection conn = DataSourceContextHolder.getConnection();
        return new ConnectionHolder(conn);
    }

    protected void doBegin(Object transaction, TransactionDefinition definition) {
        ConnectionHolder conHolder = (ConnectionHolder) transaction;
        conHolder.setAutoCommit(false);  // 开启事务
    }
}

最佳实践

  • 连接泄漏防护:包装Connection,在finally块强制归还连接池
  • 事务传播机制:使用Spring的TransactionSynchronizationManager管理嵌套事务
  • 降级策略:主库不可用时自动切换到备库并记录告警
  • 性能优化:为只读操作指定从库,通过AOP注解实现:
    @DataSource(name="slave", readOnly=true)

常见错误

错误类型后果解决方案
未清除ThreadLocal后续请求数据源污染try-finally中强制清理
跨数据源事务部分提交部分回滚使用Seata等分布式事务框架
连接未关闭连接池耗尽代理Connection.close()自动归还

扩展知识

  • XA事务处理:通过JTA实现多资源管理器协调
  • 健康检查机制:定时PING数据库检测存活状态
  • 负载均衡策略:基于权重的从库选择算法
  • Spring Boot集成:通过AbstractRoutingDataSource简化实现