dxi通用单据处理实现

处理是指数据层面而非业务层面.是业务处理,接口交换(dd,dxi_change_log等)功能的基础.
单据交换系统实际上是一个业务数据对象的同步子系统.业务系统在其上构建.
同步是基于对象的变更进行的。

对象分为单表对象,多表对象.单表对象对应表的一条记录,如商品资料.多表对象是关系型对象,关系的逻辑结构呈现树型.
多表对象是每对象分别处理(抽取,传输,接收处理),单表支持组合以提高效率.

关于dxi变更类型的概念,见http://blog.csdn.net/wherwh/article/details/41467363.

这里仅对多表对象的单据几种变更的处理实现进行说明。

.新增:
 执行插入,事务过程中如果有主键冲突,则根据主键冲突处理规则(忽略,重试,更新)决定后续动作。
 更新采用全量修改。
.全量修改:
  先删除对象记录,然后执行插入。
.增量修改:
  只对从表而言。主表主键冲突时,忽略此错误继续处理从表。
  从表按insert处理,如果出现主键冲突,则失败.
  (gyb已经增加了支持从表冲突时更新,该实现需要优化,方向之一是不能因此放弃数据库批插入的特性而影响性能)
  增量修改适用于补明细数据的情形.

接口方式:
.dd:直接面向数据源的接口方式,只能支持有限的变更类型.如无法支持删除.
删除对应的业务术语可能是废除,取消,可以通过局部修改(OM_SLIGHT_CHANGE)实现.
.dxi_chaneg_log:基于变更的接口方式,包含变更类型信息.可支持所有的变更类型,但目前有的因没有需求而未实现.

对于dd,从das 2.0开始可以在抽取规则中指定变更类型,支持新增,增量修改,全表更新(仅对单表).全表更新是das 2.0新增的.
变更类型在抽取规则的<ChangeMode>配置.默认未指定.

此前的系统包括gyb和das,只支持新增和增量修改.
增量修改是由抽取规则的f023n_5606指定的,f023n_5606=1表示增量处理,对应变更类型为OM_INC,否则为OM_NEW.默认非增量方式.

为保证兼容性,das 2.0先检查f023n_5606的值,如果配置了<ChangeMode>,则覆盖f023n_5606的设置.

以下代码反映了上面3种变更的处理差异.

单据数据处理入口函数
int CSheet::ProcessImport(CMsg *msg,CSheetDealResult &sdr)  {
 USEDBC(pdbor,this->dbc_name_.c_str());
 int result = 0;
 switch(op_type_) {
  case OM_UNSPECIFED:
  case OM_NEW:
   result = HandleNew(msg,sdr);
   break;
  case OM_DELETE:
   result = HandleDelete(msg,sdr);
   break;
  case OM_OVERWRITE:
   result = HandleUpdate(msg,sdr);
   break;
  case OM_PK_CHANGED:
   result = HandlePKChange(msg,sdr);
   break;
  case OM_INC:
   result = HandleIncChange(msg,sdr,1); ///< @note 第3个参数为flag=1,表示忽略主键冲突
   break;
  case OM_SLIGHT_CHANGE:
   result = HandleSlightChange(msg,sdr);
   break;
  case OM_FULL_SYNC:
   result = HandleFullSync(msg,sdr);
   break;
 }

 return result;
}

新增处理函数
int CSheet::HandleNew(CMsg *msg,CSheetDealResult &sdr) {
 USEDBC(pdbor,this->dbc_name_.c_str());
 FAIL_RETURN(pdbor->BeginTrans(),,-1);

 if (HandleIncChange(msg,sdr,0)) { ///< @note 第3个参数为flag=0,表示不忽略主键冲突
  pdbor->RollbackTrans();
  return -2;
 }

 FAIL_RETURN(pdbor->CommitTrans(),,-1);

 return 0;
}

全量修改处理函数

int CSheet::HandleUpdate(CMsg *msg,CSheetDealResult &sdr) {
 USEDBC(pdbor,this->dbc_name_.c_str());
 FAIL_RETURN(pdbor->BeginTrans(),,-1);
 if (HandleDelete(msg,sdr)) {
  pdbor->RollbackTrans();
  return -1;
 }
 if (Insert_v2(msg,1)) {
  pdbor->RollbackTrans();
  return -1;
 }
 FAIL_RETURN(pdbor->CommitTrans(),,-1);

 return 0;
}

int CMultiSheet::HandleIncChange(CMsg *msg,CSheetDealResult &sdr,int flag) {
 USEDBC(pdbor,this->dbc_name_.c_str());
 FAIL_RETURN(pdbor->BeginTrans(),,-1);
 if (Insert_v2(msg,flag)) {
  if ((last_errno_!=CE_PRIKEY_REPEAT)||(on_dup_key_==2)) {
   pdbor->RollbackTrans();
   return -2;
  }
   if (on_dup_key_==1) {
   sdr.result_ = 1; ///< 忽略此错误
   pdbor->RollbackTrans();
   return -3;
  }
  else { ///< 3: 按更新处理:先删除再insert
   if (HandleDelete(msg,sdr)) {
    pdbor->RollbackTrans();
    return -3;
   }
   if (Insert_v2(msg,0)) {
    pdbor->RollbackTrans();
    return -4;
   }
  }
 }

 FAIL_RETURN(pdbor->CommitTrans(),,-1);

 return 0;
}

 

Insert_v2有非通用单据处理实现的痕迹,实现上有优化空间.所有以“_2"作为名字后缀的函数都是如此安排的.

(单据处理实现经历了无类型,类体系,通用处理3个阶段,每次过渡都需要考虑兼容,导致修改的不彻底)
int CMultiSheet::Insert_v2(CMsg *msg,short flag) {
 CRowset *rs1 = msg->GetRowset(0);
 assert(rs1!=0);
 unsigned long rec_count = rs1->GetRSMeta(RST_ROW_CNT);
 assert(rec_count==1);

 const char *sheet_id_name = env_->GetSysFieldMgr()->GetField(SF_SHEET_ID);
 if (rs1->HasField(sheet_id_name)) {
  this->master_->sheet_id_ = rs1->GetFieldValueByName(0,sheet_id_name);
 }

 int result = 0;
 CPreSQLInfo psi;
 if (PrepareSQL_v2(&psi,rs1,0))
  return -1;

 string sql = LogMsg("insert into %s(%s) values(%s)", this->sheet_type_info_->master_tbl_name(),psi.fld_list_.c_str(), psi.val_list_.c_str()); 

 USEDBC(pdbor,this->dbc_name_.c_str());
 FAIL_RETURN(pdbor->BeginTrans(),,-1);

 bool br = pdbor->Execute(adCmdText, sql.c_str());
 if (!br) {
  DWORD last_error = pdbor->GetLastErrorCode();
  if (pdbor->GetDBExt()->IsDuplicateKeyError(last_error)) {
   last_errno_ = CE_PRIKEY_REPEAT;
  }
  ///< 如果非主键冲突错误且不能忽略主表主键冲突,则失败返回
  if (flag==0||last_errno_!=CE_PRIKEY_REPEAT) {
   GetThisLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"数据导入(单据类型:%d,单据编号:%s)保存数据时执行%s失败.错误:%s.\n",
    this->sheet_type_info_->type(),this->GetSheetID(), sql.c_str(),pdbor->GetLastError());
   pdbor->RollbackTrans();
   return -1;
  }
  last_errno_ = 0; ///< 重置错误码
  /// 继续
  /// 后续操作成功仍可提交
 }

 unsigned short detail_num = this->sheet_type_info_->get_tbl_num()-1;
 for (unsigned short detail_idx=0;detail_idx<detail_num;detail_idx++) {
  CRowset *prs = msg->GetRowset(1+detail_idx);
  unsigned long rec_count = prs->GetRSMeta(RST_ROW_CNT);
  CLargeStringArray vs;
  CPreSQLInfo psi;
  for (unsigned int i = 0; i < rec_count; i++) {
   psi.Reset();
   if (PrepareDetailSQL_v2(&psi,prs,i,detail_idx)) {
    pdbor->RollbackTrans();
    return -3;
   }
   char *buffer = 0;
   FormatString(2048,&buffer,"%s",psi.val_list_.c_str());
   vs.Add(buffer);
  }
  if (pdbor->GetDBExt()->BatchInsert(this->sheet_type_info_->get_tbl_name(detail_idx+1),psi.fld_list_.c_str(),vs,BATCH_INSERT_NUM)) {
   DWORD last_error = pdbor->GetLastErrorCode();
   if (pdbor->GetDBExt()->IsDuplicateKeyError(last_error)) {
    last_errno_ = CE_PRIKEY_REPEAT;
   }
   if (flag==0||last_errno_!=CE_PRIKEY_REPEAT) {
    GetThisLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"CDualSheet::Save失败,错误:%s.\n",pdbor->GetLastError());
    pdbor->RollbackTrans();
    return -1;
   }
   else ///< 从表也允许忽略主键冲突
    last_errno_ = 0;
  }
 }

 FAIL_RETURN(pdbor->CommitTrans(),,-1);

 return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值