天气项目复盘(2)

数据入库子系统

重点:只有配置文件还有等待入库的表,那么该如何凭借出SQl将每一条语句存放进入表中。
流程1:将配置文件加载到容器中,每一个文件将会有对应将要入库的表。
2.通过数据字典,清晰的解析出每一个表的字段还有信息。
3.循环将每一个文件更新到表中。
4.找到文件对应的表的信息。
5.解析该表的字段还有信息。(由于解析出来的字段信息,可以得出每一个字段内容的大小,因此动态的去绑定每一个内存空间)
6.拼接SQL语句
7.绑定参数
注意:对于内存空间的绑定其实也是与数据字典的结果一一对应
从以下可以看到,是针对于数据字典的字段,将读进来的那一段进行拆分到不同的内存,因此,注意,内容应该与表的字段一一对应,但是顺序可以不一致,不管怎样的顺序,都是按照数据字典解析的,进行拆分,因此,字段名要一样,但是顺序可以不一致。

// 解析xml,存放在已绑定的输入变量strcolvalue数组中。
void splitbuffer(char *strBuffer)
{
  // 初始化strcolvalue数组。
  for (int ii = 0; ii < TABCOLS.m_allcount; ii++)
    memset(strcolvalue[ii], 0, TABCOLS.m_vallcols[ii].collen + 1);

  char strtemp[31];

  for (int ii = 0; ii < TABCOLS.m_vallcols.size(); ii++)
  {
    // 如果是日期时间字段,提取数值就可以了。
    // 也就是说,xml文件中的日期时间只要包含了yyyymmddhh24miss就行,可以是任意分隔符。
    if (strcmp(TABCOLS.m_vallcols[ii].datatype, "date") == 0)
    {
      GetXMLBuffer(strBuffer, TABCOLS.m_vallcols[ii].colname, strtemp, TABCOLS.m_vallcols[ii].collen);
      PickNumber(strtemp, strcolvalue[ii], false, false);
      continue;
    }

    // 如果是数值字段,只提取数字、+-符号和圆点。
    if (strcmp(TABCOLS.m_vallcols[ii].datatype, "number") == 0)
    {
      GetXMLBuffer(strBuffer, TABCOLS.m_vallcols[ii].colname, strtemp, TABCOLS.m_vallcols[ii].collen);
      PickNumber(strtemp, strcolvalue[ii], true, true);
      continue;
    }

    // 如果是字符字段,直接提取。
    GetXMLBuffer(strBuffer, TABCOLS.m_vallcols[ii].colname, strcolvalue[ii], TABCOLS.m_vallcols[ii].collen);
  }
}

最终将数据入库到对应的表中。
要求:文件内部的格式应该和表的文件格式是一样的,但是顺序可以不一样,因为对于一段数据,最终也会按照数据字典的结果进行拆分,因此尽管会不同,也会查分到对应的内存中,最终绑定到sql语句中,实现数据上传。

数据同步子系统

数据同步子系统,又叫数据复制子系统,从主库中拿到不同业务的表,形成具有不同业务的表。
最难的功能实现:
1.全量同步功能,包括,不分批和分批同步
2.增量同步功能。
这里是有顺序的,也就是说,顺序不可以乱,本地表中的字段对应远程表的那个字段都是有映射的,不然无法按照顺序将数据同步到本地表中的。
顺序中隐藏了“对应关系”。

全量同步功能

不分批同步

1.首先删除那些要同步的数据项。
2.然后查找远程表的数据插入大本地表中。

// 如果是不分批同步,表示需要同步的数据量比较少,执行一次SQL语句就可以搞定。
  if (starg.synctype == 1)
  {
    logfile.Write("sync %s to %s ...", starg.lnktname, starg.localtname);

    // 先删除starg.localtname表中满足where条件的记录。
    stmtdel.prepare("delete from %s %s", starg.localtname, starg.where);
    if (stmtdel.execute() != 0)
    {
      logfile.Write("stmtdel.execute() failed.\n%s\n%s\n", stmtdel.m_sql, stmtdel.m_cda.message);
      return false;
    }

    // 再把starg.lnktname表中满足where条件的记录插入到starg.localtname表中。
    stmtins.prepare("insert into %s(%s) select %s from %s %s", starg.localtname, starg.localcols, starg.remotecols, starg.lnktname, starg.where);
    if (stmtins.execute() != 0)
    {
      logfile.Write("stmtins.execute() failed.\n%s\n%s\n", stmtins.m_sql, stmtins.m_cda.message);
      connloc.rollback(); // 如果这里失败了,可以不用回滚事务,connection类的析构函数会回滚。
      return false;
    }

    logfile.WriteEx(" %d rows in %.2fsec.\n", stmtins.m_cda.rpc, Timer.Elapsed());

    connloc.commit();

    return true;
  }

分批同步

分批同步的时候用到许多参数。

char remoteconnstr[101]; // 远程数据库的连接参数。
  char remotetname[31];    // 远程表名。
  char remotekeycol[31];   // 远程表的键值字段名。
  char localkeycol[31];    // 本地表的键值字段名。
  int maxcount;            // 每批执行一次同步操作的记录数。

远程表的键值字段名
本地表的键值字段名
主要方法是:通过键值字段名,首先查出有哪些主键是满足条件的
2.然后再通过远程表和主键子查询到哪些字段满足哪些主键
3.最后将那个子查询的表存放进入本地表

/这里将每一个进行内存绑定
  //使用远程引擎查找到在其中的记录
  //然后插入到表中
  stmtins.prepare("insert into %s(%s) select %s from %s where %s in (%s)", starg.localtname, starg.localcols, starg.remotecols, starg.fedtname, starg.remotekeycol, bindstr);
  for (int ii = 0; ii < starg.maxcount; ii++)
  {
    stmtins.bindin(ii + 1, keyvalues[ii], 50);
  }

增量同步

使用远程表

几乎和上面没有差别,通过主键查找到有哪些主键满足条件
2.然后子查询出一个表
3.将子查询的表入库到本地表中

不使用远程引擎

直接查询的是满足条件的字段的值
2.然后直接将那个值存放进入本地表

sqlstatement stmtins(&connloc); // 向本地表中插入数据的SQL语句。
  stmtins.prepare("insert into %s(%s) values(%s)", starg.localtname, starg.localcols, bindstr);
  for (int ii = 0; ii < colcount; ii++)
  {
    stmtins.bindin(ii + 1, colvalues[ii], TABCOLS.m_maxcollen);
  }

  if (stmtsel.execute() != 0)
  {
    logfile.Write("stmtsel.execute() failed.\n%s\n%s\n", stmtsel.m_sql, stmtsel.m_cda.message);
    return false;
  }

  //使用这样的好处是
  while (true)
  {
    memset(colvalues, 0, sizeof(colvalues));

    // 获取需要同步数据的结果集。
    if (stmtsel.next() != 0)
      break;

    // 向本地表中插入记录。
    if (stmtins.execute() != 0)
    {
      // 执行向本地表中插入记录的操作一般不会出错。
      // 如果报错,就肯定是数据库的问题或同步的参数配置不正确,流程不必继续。
      logfile.Write("stmtins.execute() failed.\n%s\n%s\n", stmtins.m_sql, stmtins.m_cda.message);
      return false;
    }

    // 每1000条提交一次。
    if (stmtsel.m_cda.rpc % 1000 == 0)
    {
      connloc.commit();
      PActive.UptATime();
    }
  }

相当于每一次的查询的结果就是那一条记录,然后直接将那条记录凭借上去,最后直接进入本地表中。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值