GridDB 写入约 10MB STRING 报错 60079 的原因是什么?
结论:10MB 超出文档中的 STRING 上限
GridDB 的 STRING 列值有大小限制,按 UTF-8 编码后的字节数计算。以 GridDB 5.7 官方文档为例,上限随数据库块大小变化:
| 数据库块大小 | 单个 STRING 列值上限 |
|---|---|
| 64KB | 31KB |
| 1MB、4MB、8MB、16MB、32MB | 128KB |
这些限制针对单个字段值。即使块大小为 32MB,单个 STRING 也不能存储 32MB。上述数值来自 GridDB 5.7 Features Reference。实际环境只给出了“5.x”,还需对照具体小版本的文档。
约 10MB 的字符串超过了这些上限,写入失败符合超限情形。不过,同一份文档中的上限也低于约 1MB,因此还需单独核实“约 1MB 可以成功写入”的情况,不能据此推断 GridDB 的限制介于 1MB 和 10MB 之间。
60079 能否直接确定为字符串超限?
60079 DS_TIM_ROW_DATA_INVALID 表示行注册失败,列值超过允许范围是可能的原因之一。官方还要求检查实际 schema、客户端与服务端版本,以及字符串、BLOB、数组等数据的大小或取值范围。因此,这个错误码支持“字段超限”的判断,但不能单凭它确定具体是哪项限制。GridDB 错误码说明
在给出的代码中,payload 是最需要检查的字段。服务端与客户端版本相同,也不会取消 STRING 的容量限制。
先核实写入长度和实际 schema
在 container.put(row) 前记录字符数与 UTF-8 字节数:
import java.nio.charset.StandardCharsets;
byte[] bytes = payload.getBytes(StandardCharsets.UTF_8);
System.out.println("UTF-16 code units: " + payload.length());
System.out.println("UTF-8 bytes: " + bytes.length);
示例中的字符串完全由 ASCII 字符 A 组成,1_000_000 个字符对应 1_000_000 个 UTF-8 字节,10_000_000 个字符对应 10_000_000 个 UTF-8 字节。中文等内容的字节数可能不同,不能统一用 String.length() 判断是否超限。
然后按以下顺序排查:
- 确认服务端和实际加载的 Java client JAR 的完整版本号。
- 使用
store.getContainerInfo(containerName)检查服务端已有容器的列名、列顺序和类型,确认payload确实为GSType.STRING。 - 检查写入目标集群、数据库与容器名称,确认两次测试使用同一环境,且写入前没有截断或转换数据。
- 若关闭了自动提交,确认已成功执行
commit(),再从数据库读回数据,比较完整长度和内容。 - 保存完整异常及对应的服务端日志。若约 1MB 的 STRING 仍能稳定写入并完整读回,应结合具体版本继续调查,现有材料不足以解释这一差异。
大文本可改用 BLOB
如果需要整体存储和读取约 10MB 的文本,可以将 UTF-8 字节保存为 BLOB。GridDB 5.7 文档列出的 BLOB 上限为 1GB - 1Byte;这只是类型上限,实际写入仍受内存、通信和超时等条件影响。GridDB 数据类型限制
下面的示例假设 store 已连接、payload 已生成,并使用一个新的容器名称。新容器的第二列为 GSType.BLOB:
import com.toshiba.mwcloud.gs.*;
import java.nio.charset.StandardCharsets;
import java.sql.Blob;
import java.util.Arrays;
ContainerInfo info = new ContainerInfo();
info.setType(ContainerType.COLLECTION);
info.setColumnInfoList(Arrays.asList(
new ColumnInfo("id", GSType.STRING),
new ColumnInfo("payload", GSType.BLOB)
));
info.setRowKeyAssigned(true);
try (Container<String, Row> blobs =
store.putContainer("payload_blob", info, false)) {
blobs.setAutoCommit(true);
byte[] bytes = payload.getBytes(StandardCharsets.UTF_8);
Blob blob = blobs.createBlob();
try {
blob.setBytes(1L, bytes);
Row row = blobs.createRow();
row.setString(0, "device-1");
row.setBlob(1, blob);
blobs.put(row);
} finally {
blob.free();
}
}
Container.createBlob()、Blob.setBytes() 和 Row.setBlob() 的用法见 GridDB Java API Reference。读取时用相同的 UTF-8 编码恢复字符串。
调整方案时的注意事项
- 已有 STRING 列不会因为调用
setBlob()自动变成 BLOB。应创建符合新 schema 的容器,并安排数据迁移。 - BLOB 适合保存完整内容。如果需要对文本内容做筛选或搜索,应另存用于查询的字段。
- STRING、UTF-8 字节数组和 BLOB 的处理过程会占用内存,应以实际负载验证资源需求。
- 增大块大小仍无法让上述 STRING 上限达到 10MB。
storeBlockSize也是数据库结构参数,不能在首次启动后随意修改,详见 GridDB 参数说明。
备注:内容仅供参考。
