示例#1
0
 private boolean checkNeedDbForRowMode(Pipeline pipeline, EventData eventData) {
   // 获取数据表信息
   DataMedia dataMedia = ConfigHelper.findDataMedia(pipeline, eventData.getTableId());
   DbDialect dbDialect =
       dbDialectFactory.getDbDialect(pipeline.getId(), (DbMediaSource) dataMedia.getSource());
   Table table = dbDialect.findTable(eventData.getSchemaName(), eventData.getTableName());
   if (table.getColumnCount() == eventData.getColumns().size() + eventData.getKeys().size()) {
     return false;
   } else {
     return true;
   }
 }
示例#2
0
  @Override
  public void extract(DbBatch dbBatch) throws ExtractException {
    Assert.notNull(dbBatch);
    Assert.notNull(dbBatch.getRowBatch());
    // 读取配置
    Pipeline pipeline = getPipeline(dbBatch.getRowBatch().getIdentity().getPipelineId());
    boolean mustDb = pipeline.getParameters().getSyncConsistency().isMedia();
    boolean isRow = pipeline.getParameters().getSyncMode().isRow(); // 如果是行记录是必须进行数据库反查
    // 读取一次配置
    adjustPoolSize(pipeline.getParameters().getExtractPoolSize()); // 调整下线程池,Extractor会被池化处理
    ExecutorCompletionService completionService = new ExecutorCompletionService(executor);

    // 进行并发提交
    ExtractException exception = null;
    // 每个表进行处理
    List<DataItem> items = new ArrayList<DataItem>();
    List<Future> futures = new ArrayList<Future>();
    List<EventData> eventDatas = dbBatch.getRowBatch().getDatas();
    for (EventData eventData : eventDatas) {
      if (eventData.getEventType().isDdl()) {
        continue;
      }

      DataItem item = new DataItem(eventData);
      // 针对row模式,需要去检查一下当前是否已经包含row记录的所有字段,如果发现字段不足,则执行一次数据库查询
      boolean flag =
          mustDb
              || (eventData.getSyncConsistency() != null
                  && eventData.getSyncConsistency().isMedia());

      // 增加一种case, 针对oracle erosa有时侯结果记录只有主键,没有变更字段,需要做一次反查
      if (!flag && CollectionUtils.isEmpty(eventData.getUpdatedColumns())) {
        DataMedia dataMedia = ConfigHelper.findDataMedia(pipeline, eventData.getTableId());
        if (dataMedia.getSource().getType().isOracle()) {
          flag |= true;
          eventData.setRemedy(true); // 针对这类数据,也统一视为补救的操作,可能erosa解析时反查数据库也不存在记录
        }
      }

      if (isRow && !flag) {
        // 提前判断一次,避免进入多线程进行竞争
        // 针对view视图的情况,会有后续再判断一次
        flag = checkNeedDbForRowMode(pipeline, eventData);
      }

      if (flag
          && (eventData.getEventType().isInsert()
              || eventData.getEventType().isUpdate())) { // 判断是否需要反查
        Future future =
            completionService.submit(new DatabaseExtractWorker(pipeline, item), null); // 提交进行并行查询
        if (future.isDone()) {
          // 立即判断一次,因为使用了CallerRun可能当场跑出结果,针对有异常时快速响应,而不是等跑完所有的才抛异常
          try {
            future.get();
          } catch (InterruptedException e) {
            cancel(futures); // 取消完之后立马退出
            throw new ExtractException(e);
          } catch (ExecutionException e) {
            cancel(futures); // 取消完之后立马退出
            throw new ExtractException(e);
          }
        }

        futures.add(future); // 记录一下添加的任务
      }

      items.add(item); // 按顺序添加
    }

    // 开始处理结果
    int index = 0;
    while (index < futures.size()) { // 循环处理发出去的所有任务
      try {
        Future future = completionService.take(); // 它也可能被打断
        future.get();
      } catch (InterruptedException e) {
        exception = new ExtractException(e);
        break; // 如何一个future出现了异常,就退出
      } catch (ExecutionException e) {
        exception = new ExtractException(e);
        break; // 如何一个future出现了异常,就退出
      }

      index++;
    }

    if (index < futures.size()) {
      // 小于代表有错误,需要对未完成的记录进行cancel操作,对已完成的结果进行收集,做重复录入过滤记录
      cancel(futures);
      throw exception;
    } else {
      // 全部成功分支, 构造返回结果也要保证原始的顺序
      for (int i = 0; i < items.size(); i++) {
        DataItem item = items.get(i);
        if (item.filter) { // 忽略需要被过滤的数据,比如数据库反查时记录已经不存在
          eventDatas.remove(item.getEventData());
        }
      }
    }
  }
示例#3
0
    public void run() {
      try {
        MDC.put(OtterConstants.splitPipelineLogFileKey, String.valueOf(pipeline.getId()));
        Thread.currentThread()
            .setName(String.format(WORKER_NAME_FORMAT, pipeline.getId(), pipeline.getName()));
        // 获取数据表信息
        DataMedia dataMedia = ConfigHelper.findDataMedia(pipeline, eventData.getTableId());
        DbDialect dbDialect =
            dbDialectFactory.getDbDialect(pipeline.getId(), (DbMediaSource) dataMedia.getSource());
        Table table = dbDialect.findTable(eventData.getSchemaName(), eventData.getTableName());
        TableData keyTableData = buildTableData(table, eventData.getKeys());

        // oracle类型特殊处理下
        if (dbDialect instanceof OracleDialect) {
          keyTableData.columnTypes = getOraclePkTypes(table, keyTableData.columnNames);
        }

        boolean needAll =
            pipeline.getParameters().getSyncMode().isRow()
                || (eventData.getSyncMode() != null && eventData.getSyncMode().isRow());

        // 增加一种case, 针对oracle erosa有时侯结果记录只有主键,没有变更字段,需要做一次反查,获取所有字段
        needAll |=
            CollectionUtils.isEmpty(eventData.getUpdatedColumns())
                && dataMedia.getSource().getType().isOracle();

        List<DataMediaPair> mediaParis =
            ConfigHelper.findDataMediaPairByMediaId(pipeline, dataMedia.getId());
        List<String> viewColumnNames =
            buildMaxColumnsFromColumnPairs(mediaParis, eventData.getKeys());

        // TODO 后续版本测试下
        // if (needAll) {
        // boolean needDb = checkNeedDbForRowMode(table,
        // viewColumnNames, eventData);
        // if (needAll && !needDb) {// 不需要进行反查
        // item.setFilter(false);
        // return;
        // }
        // }

        // modified by ljh at 2012-11-04
        // 反查数据时只反查带update=true标识的数据,因为update=false的记录可能只是进行filter需要用到的数据,不需要反查
        TableData columnTableData =
            buildTableData(table, eventData.getUpdatedColumns(), needAll, viewColumnNames);

        if (columnTableData.columnNames.length == 0) {
          // 全主键,不需要进行反查
        } else {
          List<String> newColumnValues =
              select(
                  dbDialect,
                  eventData.getSchemaName(),
                  eventData.getTableName(),
                  keyTableData,
                  columnTableData);

          if (newColumnValues == null) {
            // miss from db
            // 设置为filter=true,可能存在丢数据的风险.
            // 比如针对源库发生主备切换,otter反查的是备库,查询不到对应的记录
            // item.setFilter(true);

            // 针对需要自定义反查数据库的,允许忽略
            // a. 自由门触发的数据,不存在时可以忽略
            // b. 回环补救算法触发的数据,不存在时可以忽略
            boolean needFilter = eventData.isRemedy() || pipeline.getParameters().getSkipNoRow();
            item.setFilter(needFilter);

            // 判断主键是否有变更,如果变更了,就原样返回item
            int index = 0;
            for (EventColumn oldKey : eventData.getOldKeys()) {
              if (!oldKey.equals(eventData.getKeys().get(index))) {
                item.setFilter(false);
                break;
              }
            }
          } else {
            // 构造反查的返回结果
            List<EventColumn> newEventColumns = new ArrayList<EventColumn>();
            for (int i = 0; i < newColumnValues.size(); i++) {
              EventColumn column = new EventColumn();
              column.setIndex(columnTableData.indexs[i]);
              column.setColumnName(columnTableData.columnNames[i]);
              column.setColumnType(columnTableData.columnTypes[i]);
              column.setNull(newColumnValues.get(i) == null);
              column.setColumnValue(newColumnValues.get(i));
              column.setUpdate(true);
              newEventColumns.add(column);
            }

            // 处理下columns中不在反查字段内的字段列表
            for (EventColumn column : eventData.getColumns()) {
              boolean override = false;
              for (EventColumn newEventColumn : newEventColumns) {
                if (StringUtils.equalsIgnoreCase(
                    newEventColumn.getColumnName(), column.getColumnName())) {
                  override = true;
                  break;
                }
              }

              if (!override) { // 针对newcolumns不存在的记录进行添加
                newEventColumns.add(column);
              }
            }

            Collections.sort(newEventColumns, new EventColumnIndexComparable()); // 重新排个序
            eventData.setColumns(newEventColumns);
          }
        }
      } catch (InterruptedException e) {
        // ignore
      } finally {
        Thread.currentThread().setName(WORKER_NAME);
        MDC.remove(OtterConstants.splitPipelineLogFileKey);
      }
    }