开源一个超好用的数据核对/对账框架

项目地址:github.com/starslink/d...

🚀 高性能、多策略的数据对账框架,支持内存、流式、并行、Redis、数据库等多种处理方式

✨ 特性

  • 🎯 多种对账策略 - 内存、流式、并行、Redis、数据库、增量处理
  • 🔧 灵活配置 - 支持注解和适配器两种数据定义方式
  • 📊 性能优化 - 根据数据量自动选择最优处理策略
  • 🌐 分布式支持 - Redis分布式缓存,支持集群部署
  • 💾 内存友好 - 流式处理避免大数据量内存溢出
  • 高并发 - 多线程并行处理,充分利用CPU资源

🚀 快速开始

1. 添加依赖

xml 复制代码
<dependency>
  <groupId>com.starslink</groupId>
  <artifactId>data-check</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

2. 基础使用

java 复制代码
// 创建对账配置
CheckConfig config = CheckConfig.builder()
        .id("order-check")
        .name("订单对账")
        .srcLoader(date -> loadSourceData(date))      // 源数据加载器
        .targetLoader(date -> loadTargetData(date))   // 目标数据加载器
        .allowableErrorRange(BigDecimal.valueOf(0.01)) // 允许误差
        .checkAfter(context -> {
          // 处理对账结果
          System.out.println("发现差异: " + context.getCheckResult().getDiffDetails().size());
        })
        .build();

// 执行对账
CheckExecutor executor = CheckExecutor.buildExecutor(config);
CheckContext result = executor.process("2023-12-01");

3. 数据实体定义

方式一:使用注解

java 复制代码
public class Order {

  @CheckIdentity
  private String orderId;

  @CheckField(order = 1)
  private BigDecimal amount;

  @CheckField(order = 2)
  private String status;
}

方式二:实现适配器

java 复制代码
public class OrderAdapter implements CheckAdapter {

  @Override
  public String getKey() {
    return orderId;
  }

  @Override
  public Map<String, Object> getCheckData() {
    return MapUtil.of("amount", amount, "status", status);
  }
}

📊 处理器选择

处理器类型 适用数据量 主要特点 使用场景
Memory < 10万 全内存,速度最快 小数据量,实时对账
Stream 10万-100万 分批处理,内存友好 大数据量,防止OOM
Parallel 任意 多线程并行 CPU密集型,追求速度
Redis 任意 分布式缓存 集群环境,数据共享
Database > 100万 SQL优化 超大数据量
Incremental 任意 增量处理 定期对账,减少计算

🔧 高级配置

流式处理(推荐大数据量)

java 复制代码
CheckConfig config = CheckConfig.builder()
    .id("stream-check")
    .batchSize(5000)  // 批次大小
    .checkProcessor(new StreamCheckProcessor())
    .build();

并行处理(推荐多核CPU)

java 复制代码
CheckConfig config = CheckConfig.builder()
    .id("parallel-check")
    .isAsync(true)
    .checkProcessor(new ParallelCheckProcessor())
    .build();

Redis分布式处理

java 复制代码
CheckConfig config = CheckConfig.builder()
    .id("redis-check")
    .checkCacheEnum(CheckCacheEnum.REDIS)
    .redisConfig(redisConfig)
    .build();

数据库处理(超大数据量)

java 复制代码
CheckConfig config = CheckConfig.builder()
    .id("database-check")
    .checkProcessor(new DatabaseCheckProcessor(dataSource))
    .build();

增量处理

java 复制代码
IncrementalDataProvider provider = new MyIncrementalDataProvider();
CheckConfig config = CheckConfig.builder()
    .id("incremental-check")
    .checkProcessor(new IncrementalCheckProcessor(provider))
    .build();

🎯 智能选择策略

java 复制代码
public CheckProcessor selectOptimalProcessor(int dataSize) {
  if (dataSize < 10_000) {
    return new MemoryCheckProcessor();           // 小数据量
  } else if (dataSize < 100_000) {
    return new ParallelCheckProcessor();         // 中等数据量
  } else if (dataSize < 1_000_000) {
    return new StreamCheckProcessor();           // 大数据量
  } else {
    return new DatabaseCheckProcessor(dataSource); // 超大数据量
  }
}

📈 性能对比

makefile 复制代码
数据量: 100万条记录测试结果

Memory处理器:    ❌ OutOfMemoryError
Stream处理器:    ✅ 45秒, 内存占用: 200MB
Parallel处理器:  ✅ 28秒, 内存占用: 800MB  
Database处理器:  ✅ 35秒, 内存占用: 50MB

🛠️ 完整示例

java 复制代码
@Test
public void testOrderReconciliation() {
  // 模拟数据
  List<Order> sourceOrders = loadOrdersFromSystem1("2023-12-01");
  List<Order> targetOrders = loadOrdersFromSystem2("2023-12-01");

  // 配置对账
  CheckConfig config = CheckConfig.builder()
      .id("daily-order-check")
      .name("每日订单对账")
      .srcLoader(date -> CheckEntry.wrap(sourceOrders))
      .targetLoader(date -> CheckEntry.wrap(targetOrders))
      .allowableErrorRange(BigDecimal.valueOf(0.01))
      .checkProcessor(selectOptimalProcessor(sourceOrders.size()))
      .checkPre(context -> validateData(context))
      .checkAfter(context -> {
        CheckResult result = context.getCheckResult();
        generateReport(result);
        sendNotification(result);
      })
      .build();

  // 执行对账
  CheckExecutor executor = CheckExecutor.buildExecutor(config);
  CheckContext result = executor.process("2023-12-01");

  // 输出结果
  System.out.println("对账完成:");
  System.out.println("- 源数据: " + result.getSource().size());
  System.out.println("- 目标数据: " + result.getTarget().size());
  System.out.println("- 差异记录: " + result.getCheckResult().getDiffDetails().size());
}
相关推荐
努力的小郑1 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Victor3562 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3562 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁2 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp2 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴4 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友4 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒5 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
Soofjan6 小时前
Go 内存回收-GC 源码1-触发与阶段
后端
shining6 小时前
[Golang]Eino探索之旅-初窥门径
后端