数据入库子系统
重点:只有配置文件还有等待入库的表,那么该如何凭借出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();
}
}
相当于每一次的查询的结果就是那一条记录,然后直接将那条记录凭借上去,最后直接进入本地表中。