批量操作接口的相关说明

批量操作接口的相关说明

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

1. 接口分类

1.1 Generic 表批量接口

接口类型处理语义说明
BatchGet读拆成多个 GetTDR 表可指定返回部分一级字段;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 填充则不需要 Pack;BatchGet / 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.DoBatchUpdate 等 DoBatch* 系列 + 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 SDKTcaplusServiceRequest::SetMultiResponseFlag(1)
C++ PB SDKTcaplusPbMessageOption::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 的分错误码无法读到
BatchGetC++ 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 SDKSDK 超时后触发超时回调
C++ TDR SDK业务自行实现请求超时判断
Go SDK同步接口直接返回超时错误

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

7. 性能与使用建议

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

建议:

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

8. 接口文档与示例

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

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

接口文档
BatchGetGeneric 表批量查询多条数据
BatchInsertGeneric 表批量插入多条数据
BatchUpdateGeneric 表批量更新多条数据
BatchReplaceGeneric 表批量替换多条数据
BatchDeleteGeneric 表批量删除多条数据
ListAddAfterBatchList 表向列表中批量插入元素
ListGetBatchList 表从列表中批量查询元素
ListReplaceBatchList 表向列表中批量更新元素
ListDeleteBatchList 表从列表中批量删除元素