核心逻辑控制流如下,隐去了日志和微观容错
static int insert_a_table(T_SQL_Connect *db_conn, FILE *xfd)
{
char cols[4096], stmt[4096], *p, *savep;
char *tabname;
t_node node;
ctx_stu ctx;
T_Tree *cols_list = NULL;
SdbcDAO *dao;
// 1. 读取首行并提取表名
fgets(cols, sizeof(cols), xfd);
tabname = strtok_r(cols, ":", &savep);
strupper(tabname);
// 2. 动态创建 DAO:内部读表结构+修正表,计算偏移量生成虚结构布局与模板
dao = new SdbcDAO(db_conn, tabname);
dao->Data_init();
ctx.dp = dao;
node.n = 0;
// 3. 切分列名,建立平衡二叉树索引(绑定文件列与虚结构模板)
while(NULL != (p = strtok_r(NULL, ",", &savep))) {
node.tp = dao->getTemplate(p); // 提取该列的修正格式与内存偏移模板
cols_list = BB_Tree_Add(cols_list, &node, sizeof(node), node_cmp, NULL);
node.n++;
}
// 4. 逐行读数据,利用树遍历进行双向匹配与内存填充,最后插入
for(int i = 0; fgets(stmt, sizeof(stmt), xfd); i++) {
TRIM(stmt);
ctx.data = ctx.p = stmt;
// 遍历二叉树,对每个节点回调 fill_cols,切分 ctx.p 并按模板格式填入 dao 的虚结构中
BB_Tree_Count(cols_list, &ctx, fill_cols);
*stmt = 0;
dao->insert(stmt); // 触发数据库流式写入
}
// 5. 释放路由树与虚拟结构体容器
BB_Tree_Free(&cols_list, NULL);
delete dao;
return i;
}
详细技术注释版
/**
* @brief 动态模板驱动的高性能通用表数据导入函数
* @param db_conn 数据库连接句柄
* @param xfd 已经打开的结构化文本文件流
* @return int 成功插入的记录行数
*/
static int insert_a_table(T_SQL_Connect *db_conn, FILE *xfd)
{
// 定义缓冲区与流控指针
char cols[4096], stmt[4096], *p, *savep;
char *tabname;
int ret, i, n;
t_node node;
ctx_stu ctx;
T_Tree *cols_list = NULL; // 运行时列名-内存模板路由平衡二叉树
SdbcDAO *dao; // 包含模板系统与虚结构内存区的持久化核心对象
// ----------------------------------------------------------------
// 要素一:提取元数据,触发动态虚结构内存布局
// ----------------------------------------------------------------
// 读取文件第一行:元数据定义行(格式:表名:列1,列2,列3...)
if(NULL == fgets(cols, sizeof(cols), xfd)) {
ShowLog(1, " 没有数据!", __FUNCTION__);
return -1;
}
TRIM(cols); // 清除换行及尾部空白
// 截取第一部分得到表名
tabname = strtok_r(cols, ":", &savep);
if(!tabname) {
ShowLog(1, "%s: tabname is empty!", __FUNCTION__);
return -1;
}
strupper(tabname); // 标准化表名
try {
// 【核心机制:动态反射与虚结构构建】
// SdbcDAO 构造函数在底层会做三件事:
// 1. 查询数据库系统表获取该表的原生列结构(类型、长度)。
// 2. 读取“列类型修正表”,补充原生字典无法提供的特殊格式(如 Oracle 的 Date 转换格式)。
// 3. 按照编译器的内存对齐原则,动态计算各列偏移量(Offset),开辟一块 Raw 内存作为隐式 struct 缓冲区。
dao = new SdbcDAO(db_conn, tabname);
} catch( ... ) {
ShowLog(1, "%s:%s Table not found!", __FUNCTION__, tabname);
return -2;
}
dao->Data_init(); // 清空或初始化刚刚开辟的隐式 struct 内存区
ctx.dp = dao; // 传入上下文,供后续 fill_cols 寻址 dao
node.n = 0; // 文件列计数器初始化
// ----------------------------------------------------------------
// 要素二:双向匹配,构建运行时路由树
// ----------------------------------------------------------------
// 继续切分出文件中的每一个列名
while(NULL != (p = strtok_r(NULL, ",", &savep))) {
if((255 & *p) <= ' ') break;
// 核心双向匹配:用文件读出的列名去匹配 dao 内部基于表结构生成的模板
node.tp = dao->getTemplate(p);
if(!node.tp) {
// 允许不认识的数据结构存在(文件里有,数据库里没有则跳过)
ShowLog(1, "%s:%s column [%s] not found!", __FUNCTION__, tabname, p);
}
// 将包含有【内存偏移/格式转换规则(tp)】和【文件列顺序(n)】的节点挂载到平衡二叉树
// 为后续海量数据行的快速字段对齐(O(log n))做准备
cols_list = BB_Tree_Add(cols_list, &node, sizeof(node), node_cmp, NULL);
node.n++;
}
// ----------------------------------------------------------------
// 要素三:流式消费文本,利用虚结构进行批量/高频内存填充
// ----------------------------------------------------------------
// 从第二行开始,循环读取纯数据文本
for(i = 0; fgets(stmt, sizeof(stmt), xfd); i++) {
TRIM(stmt);
ctx.data = ctx.p = stmt; // 将当前行字符串首地址赋予上下文游标 ctx.p
// 【控制反转解析】
// 遍历二叉树,对树上每个列节点调用回调函数 fill_cols。
// fill_cols 内部逻辑:
// 1. 从 ctx.p 中切出当前字段的文本片段,并将 ctx.p 向后移动。
// 2. 读取节点中模板(tp)记录的格式(如特定的日期格式规则)。
// 3. 将文本进行类型转换,根据模板中的 Offset,直接写入 dao 的虚结构内存区。
ret = BB_Tree_Count(cols_list, &ctx, fill_cols);
*stmt = 0; // 清空缓冲区用于接收 dao 内部实际执行的 SQL
// 【批量优化点】
// 隐式 struct 缓冲区在内存中是固定且连续的。
// dao->insert 在第一行数据时会进行底层 SQL 的 Prepare 并 Bind 这些内存地址。
// 此时,直接执行(Execute)即可将隐式 struct 中的数据刷入数据库,效率等同于硬编码的 struct 数组。
ret = dao->insert(stmt);
if(ret < 0) {
ShowLog(1, "%s:insert %s fault,i=%d,err=%d,%s", __FUNCTION__, stmt, i,
db_conn->Errno, db_conn->ErrMsg);
break;
}
}
// ----------------------------------------------------------------
// 要素四:销毁容器,维持统一系统的内存稳定
// ----------------------------------------------------------------
BB_Tree_Free(&cols_list, NULL); // 销毁路由索引树
delete dao; // 释放隐式虚拟结构体缓冲区及模板占用的内存
return i; // 返回批量操作影响的总行数
}
【 在 DoorWay 的大作中提到: 】
: 你的系统
: ===核心思想(Main Idea)
: 实现了一个动态模板驱动的流式数据导入通道。
: ...................
--
FROM 113.132.11.*