# TDR 表数据读写与版本兼容性

> 本文聚焦 TDR 表两个易出问题但又常被忽略的兼容性主题：写入接口配对（SetData/SetValue）、跨实例 TDR 元数据版本兼容。这两点是 TDR 表特有的（PB 表无此问题）。

## 1. SetData 与 SetValue 的区别

TDR 表的 SDK 提供两种数据读写方式，必须配套使用：

- **SetData / GetData**：整条记录按 TDR 编解码，复杂类型字段（struct / union / 数组）自动在字段数据前附加 2 字节 TDR 版本号。
- **SetValue / GetValue**：按字段名逐字段读写原始 buffer，后端不做 TDR 编解码。

混用的后果：

- **SetData 写入 + GetValue 读取**：复杂类型字段的原始 buffer 包含 2 字节 TDR 版本头，GetValue 会原样返回，业务如果不知道需要跳过这 2 字节，会导致数据解析错误。
- **SetValue 写入 + GetData 读取**：SetValue 写入的 buffer 不含 TDR 版本头，GetData 尝试按 TDR 格式解包时，会因缺少版本头而解包失败或数据错乱。

## 2. TDR 表版本兼容

在普通 SetData / GetData 读写路径上，后端**不校验** TDR 数据版本与本端元数据版本是否一致，版本兼容性需业务自行保证。

典型问题场景：GameSvr-A 使用 v+1 版本 TDR 元数据通过 SetData 写入数据，GameSvr-B 本地 TDR 元数据为 v 版本，通过 GetData 读取时会因版本不兼容导致 TDR 解包失败。

**建议**：业务修改 TDR 表结构时，确保所有接入的 GameSvr 同步更新 TDR 元数据。

## 3. TDR 表条件过滤与条件更新

条件过滤（`condition`）和条件更新（`operation`）适用于 SetData / GetData 方式。其原理是：后端需要按 TDR 协议解包字段数据才能判断条件、执行 PUSH / SET / POP 等数组操作；SetData 写入的数据带有完整的 TDR 编码（包含复杂类型字段头部的 2 字节版本号），因此后端能正确解包并参与条件过滤/更新。

- **条件过滤**：支持 SQL 风格的条件表达式。若条件涉及嵌套字段（如 `a.b.c > 1`），后端需要对相应的复杂类型字段做 TDR 解包，因此要求存储数据与本端 TDR 元数据版本兼容。
- **条件更新（Operation）**：支持对数组字段的 PUSH / SET / POP 操作，包括一级数组字段和嵌套结构体内的数组字段（如 `single_struct.sub_array`）。同样要求存储数据与本端 TDR 元数据版本兼容。

关于 SetValue 写入的数据：

- **一级标量字段**（如 `int`、`string`）SetValue 写入后**仍然可以**被条件过滤命中，因为标量字段不带 2 字节 TDR 版本头，后端按字段名直接读取原始 buffer 即可判断。
- **复杂类型字段**（结构体、union、数组）SetValue 写入的 buffer 缺少 2 字节版本头，后端按 TDR 解包时会失败或拿到错乱的数据，**不建议**对 SetValue 写入的复杂字段使用条件过滤/数组更新；如需使用，请改走 SetData 写入路径。

> 完整的能力清单、命令矩阵、TDR vs PB 差异、性能优化等详情见《[条件过滤和更新功能](../06条件过滤和更新功能.md)》。

## 4. 相关文档

- 《[条件过滤和更新功能](../06条件过滤和更新功能.md)》
- 《[条件过滤和更新语法说明](../05条件过滤和更新语法说明.md)》
- 《[TDR 表 string 类型多语言兼容性](05TDR表string类型多语言兼容性.md)》
- 《[典型技术问题](../../08TcaplusDB常见问题/02典型技术问题.md)》§1：两 GameSvr 字段集不同时的 cross-write 行为（与 §2 不同维度）
