知识卡片
数据的生命周期超出代码的生命周期及未知字段丢失陷阱
内容
数据库场景下的兼容性要求比想象中更严格。首先,多进程并发访问数据库的场景下,因为 滚动升级过程中不同实例可能运行新旧不同版本的代码,向前兼容不再是可有可无的——旧版 代码有很大概率读到新版代码刚写入的数据。更根本的是一个容易被忽视的事实:”数据的 生命周期超出代码的生命周期”:应用新版本可能几分钟内就在所有节点上替换完毕,但数据库 里的内容不会自动跟着”升级”——五年前写入的记录,除非显式重写,否则依然以五年前的 原始编码格式存在磁盘上,而重写整个大数据集通常代价高昂,大多数数据库能不做就不做 (多数关系数据库支持”加一个默认值为NULL的新列”这类不需要重写现有数据的模式变更, 读到缺列的旧行时用NULL填充即可)。这意味着模式演变必须让”整个数据库看起来像是用 单一模式编码”,即使底层实际上混杂着各个历史版本模式编码的记录。第二个容易被忽视的 陷阱出现在应用层:即使编码格式本身支持保留未知字段(旧代码不认识的新增字段),如果 应用把数据库值解码成内部的模型对象、修改后再重新编码写回,这个”解码→模型对象→ 重新编码”的翻译过程很容易把不认识的字段直接丢弃——不是编码格式的问题,而是应用 代码在中间层悄悄把它弄丢了,这类问题不难解决,但必须先意识到它才能针对性防范。
参考来源
- 位置:《数据密集型应用系统设计》第四章《编码与演化》"数据库中的数据流"(源文件:
_epub-src/ch4_split_002.html)
- 结论依据:原文说明数据库中的值可能被新版本代码写入后被旧版本代码读取因而需要
向前兼容,指出"数据的生命周期超出代码的生命周期"、多数关系数据库支持不重写数据
的模式变更,并说明应用把数据库值解码为模型对象再重新编码时未知字段可能在翻译
过程中丢失,直接支撑本卡片结论。
- 原始内容:这意味着数据库中的一个值可能会被更新版本的代码写入,然后被仍旧运行的
旧版本的代码读取。因此,数据库也经常需要向前兼容……数据的生命周期超出代码的
生命周期……如果将数据库值解码为应用程序中的模型对象,稍后重新编码这些模型对象,
那么未知字段可能会在该翻译过程中丢失。