批量操作接口的相关说明

批量操作指一个请求中携带多条记录或多个 List 元素。批量接口不保证原子性,一次请求可能部分成功、部分失败,业务必须逐条检查子错误码。

1. 接口分类

1.1 Generic 表批量接口

接口 类型 处理语义 说明
BatchGet 拆成多个 Get TDR 表可指定返回部分一级字段;PB 表返回整条记录
BatchFieldGet 拆成多个 FieldGet 仅 PB 表;用于返回部分字段,含子级字段
BatchInsert 拆成多个 Insert 记录已存在则该条失败
BatchUpdate 拆成多个 Update 记录不存在则该条失败
BatchReplace 拆成多个 Replace 记录不存在则插入
BatchDelete 拆成多个 Delete 删除不存在记录时该条失败

Generic 表批量请求主要由接入层拆分、转发到存储层,再聚合多个单记录响应返回客户端。

1.2 List 表批量接口

接口 类型 处理语义 说明
ListGetBatch 同一大 key 下批量读取元素 记录不存在时继续读下一条;其他错误会终止遍历
ListAddAfterBatch 同一大 key 下批量插入元素 某条失败后继续处理下一条
ListReplaceBatch 同一大 key 下批量更新元素 目标元素不存在则该条失败;失败后继续处理下一条
ListDeleteBatch 同一大 key 下批量删除元素 某条失败后继续处理下一条

List 表批量请求都针对同一个大 key 下的多个元素,接入层透传给存储层,由存储层在一次请求中循环处理。

2. 通用限制

限制项 规则
单请求记录数 最多 1024 条记录或元素
单请求大小 不能超过 10 MB
原子性 非原子;可能部分成功、部分失败
单记录打包 C++ TDR SDK 中,若用 SetKey / SetValue 填充 BatchInsert / BatchUpdate / BatchReplace 的 record,需要再调用 record 的 Pack,用于标记该 record 已是完整记录;若用 SetData 填充则不需要 PackBatchGet / BatchDelete 不需要

3. 返回码与结果读取

批量响应包含两层错误码,业务判断每个 key 是否成功时,应以分错误码为准:

错误码 含义 获取方式
总错误码 本次批量请求的整体流程状态,例如请求解析、路由、接入层与存储层通信是否出现系统级错误 response 返回值
分错误码 单条记录或元素的执行结果,即某个 key 成功、失败、超时或条件不满足 遍历响应中的记录 / 元素时获取

总错误码和分错误码的关系:

场景 关系 业务处理
总错误码为 0 表示整体流程正常完成;不代表每个 key 都成功 继续遍历分错误码,逐条判断
总错误码非 0 且响应包中有记录 表示整体流程发生错误或超时;响应中仍可能携带已明确失败 / 超时的 key 仍要读取响应中的 key 和分错误码,比如批量Get的某个响应包的记录全是261(记录不存在),总错误码就是261,如果任意一个是0(成功),总错误码则是0,故不论何种场景,用户都需要读取分错误码判断哪个Key成功,哪个Key失败
Swift / proxy 等待存储层超时 总错误码为超时错误;proxy 会构造响应并带回超时 key 按这些 key 的分错误码标记失败 / 超时
响应包中没有出现的 key 没有对应分错误码 按本次总错误码或本地超时策略处理,不能当作成功

proxy 对普通 Batch* 写类请求的回包规则:

接口 key 是否返回 分错误码是否返回 value 是否返回
BatchInsert / BatchUpdate / BatchReplace / BatchDelete 返回 返回 recordResult[i] ResultFlag 控制
ResultFlag = NOVALUE(0) 仍返回 key 仍返回分错误码 不返回 value
Swift / 存储层响应超时 返回超时 key 返回对应超时错误码 不返回 value

因此,批量写接口的正确处理方式是:先遍历响应中每条 key 的分错误码,再决定该 key 成功还是失败。总错误码只用于判断整体流程状态,不能替代分错误码。需要控制 value 回带时,使用 SetResultFlagForSuccess / SetResultFlagForFail,详见 ResultFlag响应数据返回控制

3.1 C++ TDR SDK 示例

C++ TDR SDK 完整示例(含 RecvResponse 主循环、FetchRecord 读分错误码、HaveMoreResPkgs 续包、ScanTimeout 超时兜底)以及对应的分包丢包处理思路,参见 响应分包和丢包处理说明 §3.2.1 Generic Batch 类

3.2 C++ PB SDK 示例

C++ PB async 的批量写接口通过 TcaplusPbCallback 回调返回结果,三个回调的含义如下:

回调 触发条件 传入消息含义 业务处理
OnRecv(const std::map<Message*, int>& mapMsg) SDK 收到并成功解析一个批量响应包 mapMsg 中每个 Message* 对应一个 key,int 是该 key 的分错误码;map 内既可能有成功 key,也可能有失败 key 按 map 中的分错误码逐条判断 key 成败
OnError(const std::vector<Message*>& msgs, int errorcode) SDK/协议层遇到整批错误,或用 API_ERR_NO_MORE_RECORD 通知本次批量响应结束 msgs 是 SDK 当前保存的原始请求消息集合(实现中直接传 m_vecMsgs),不是失败消息集合;errorcode 是 SDK 回调层面的整体错误/结束码,不是 proxy 响应里的总错误码,也不是分错误码 errorcode == API_ERR_NO_MORE_RECORD 只表示结束;其他错误码表示本次批量请求在 SDK/协议层整体异常,本地仍未确认成功的 key 可按该错误码处理
OnTimeout(const std::vector<Message*>& msgs) SDK 等待响应超过超时时间 msgs 是 SDK 当前保存的请求消息集合;如果此前已收到过部分分包,它不一定精确等于“未返回 key 集合” 将本地仍未确认成功的 key 按超时处理

C++ PB SDK 完整示例(含 OnRecv 累积分错误码、OnError 处理 API_ERR_NO_MORE_RECORD 结束哨兵、OnTimeout 兜底、OnFinish 统一收口)以及 m_result 哨兵覆写思路,参见 响应分包和丢包处理说明 §3.2.1 Generic Batch 类

3.3 Go SDK 示例

Go SDK 提供两套接口:

用法 入口 接口返回值语义 分错误读取方式 适用场景
高级用法(推荐 client.DoBatchUpdateDoBatch* 系列 + option.TDROpt / option.PBOpt 只要有任一 key 失败,整体 err 就非 nil(封装的底层用法,故意如此设计的) opt.BatchResult[i](与 dataSlice[i] 一一对应) 业务代码,按 key 维度判断成败
底层用法 client.NewRequest + client.DoMore 与老的 C++ TDR 接口一致:返回的 err 只反映 SDK / 协议层错误(如等待超时、参数错误),业务错误需要自己从 resp.GetResult() + 每条 FetchRecord() 读出 遍历每个 resp.FetchRecord() 返回的 error 需要直接操作 Request / 多包遍历

高级用法内部就是封装了底层 NewRequest + DoMore,并自动把每条记录的分错误码、version 按下标回填到 opt.BatchResult / opt.BatchVersion,再把任一子失败聚合成接口级 err。两套接口最终走同一条协议链路,分错误码语义一致;但接口返回值的含义不同:高级用法是"全成功才返回 nil",底层用法是"SDK 层无错就返回 nil"。

Go SDK 完整示例(高级用法 DoBatchGet + 底层用法 NewRequest / DoMore)以及分错误码、丢包识别、超时兜底的处理思路,参见 响应分包和丢包处理说明 §3.2.1 Generic Batch 类

4. 分包行为

4.1 分包规则

规则 说明
触发条件 响应包超过 256 KB 时触发分包
单记录完整性 分包不会切分单条记录;单条记录只会出现在一个响应包中
示例 3 条记录大小分别为 10 KB、251 KB、1 MB,可能分为 (10 KB + 251 KB)(1 MB) 两个响应包

4.2 强烈建议:所有批量接口都手动开启分包

⚠️ "不允许分包" 是历史遗留的畸形设计:响应数据超过 256 KB 时,会出现只返回部分记录、ListGetBatch 提前截断等"静默丢数据"现象,但接口仍可能返回成功,业务很难感知。

为了好记,请把下面这条作为统一规则

  • 任何批量接口、任何 SDK、任何表类型,调用前都手动设置 SetMultiResponseFlag(1),由 SDK 负责收齐所有分包;
  • 不要去记忆"哪个 SDK / 哪个命令字默认是否允许分包",记一条规则比记一张表更可靠。

各 SDK 中开启分包的入口:

SDK 设置入口
C++ TDR SDK TcaplusServiceRequest::SetMultiResponseFlag(1)
C++ PB SDK TcaplusPbMessageOption::SetMultiResponseFlag(1)(或通过 SDK 封装的 SetMessageOption
Go SDK 底层用法 req.SetMultiResponseFlag(1)
Go SDK 高级用法 option.TDROpt{ MultiFlag: 1 } / option.PBOpt{ MultiFlag: 1 }

4.3 不开启分包时各接口的具体影响

不开启分包并不会让 SDK 报错,但响应数据过大时会发生静默截断,下表列出典型场景:

接口类别 不开启分包时的实际表现
Generic 表写类批量接口(BatchInsert / BatchUpdate / BatchReplace / BatchDelete 响应数据过大时只返回前若干条记录,剩余 key 的分错误码无法读到
BatchGet C++ TDR SDK 该接口本身会自动分包;其它语言 SDK 若未显式开启,可能仍受单包大小限制
ListGetBatch 累计响应超过单包大小后,直接停止读后续元素,业务以为已读完,实际丢数据
ListAddAfterBatch / ListReplaceBatch / ListDeleteBatch 写入仍会全量执行,但 ResultFlag 要求回带的记录数据可能无法全部返回

综上,所有批量接口都建议默认打开 SetMultiResponseFlag(1),不需要再按接口/SDK 区分。

5. 返回顺序

表类型 批量读返回顺序 说明
Generic 表 无序 返回顺序不保证与请求 key 顺序一致;同一个请求多次执行,返回顺序也可能不同
List 表 按 List 元素顺序 尾插场景先插入先返回;头插场景先插入后返回

6. 超时处理

接入层等待存储层单记录响应有超时时间,默认约 2 秒。超时后处理如下:

步骤 行为
1 先返回已经聚合但尚未发送的响应包
2 构造超时响应包,总错误码为超时错误(如 -7953
3 超时响应中携带超时记录的 key,之后本次批量请求结束

SDK 侧超时判断:

SDK 超时处理
Java SDK / C++ PB SDK SDK 超时后触发超时回调
C++ TDR SDK 业务自行实现请求超时判断
Go SDK 同步接口直接返回超时错误

如需调整接入层等待存储层的超时时间,请联系 DBA。

7. 性能与使用建议

对比项 批量接口 单记录接口
存储层开销 Generic 表批量请求会拆成单记录请求,存储层开销基本相同;List 表批量请求在同一大 key 内循环处理 单条请求逐个处理
平均时延 通常更高,需要等待多条记录聚合返回 通常更低
网络流量 多条记录场景可减少协议头开销 单条记录场景更省
接入层 CPU Generic 表需要拆分请求、聚合响应,接入层开销更高 接入层处理更简单

建议:

场景 推荐
一次需要处理多条记录,且业务希望减少请求数 使用批量接口
只操作 1 条记录 使用单记录接口
强依赖每条记录独立低时延 优先考虑单记录接口
任何批量接口 统一手动开启 SetMultiResponseFlag(1)(详见 §4.2)

8. 接口文档与示例

各 SDK 和 API 的具体接口说明,请参考 TcaplusDB SDK & API

常用 C++ TDR SDK 接口文档:

接口 文档
BatchGet Generic 表批量查询多条数据
BatchInsert Generic 表批量插入多条数据
BatchUpdate Generic 表批量更新多条数据
BatchReplace Generic 表批量替换多条数据
BatchDelete Generic 表批量删除多条数据
ListAddAfterBatch List 表向列表中批量插入元素
ListGetBatch List 表从列表中批量查询元素
ListReplaceBatch List 表向列表中批量更新元素
ListDeleteBatch List 表从列表中批量删除元素

results matching ""

    No results matching ""