知识卡片
集合外键更新的三种策略
内容
外键映射把对象间的引用关系映射成数据库表间的外键,单值引用(如唱片指向艺术家)很直接,但一旦对象持有的是一个集合(如唱片拥有多条曲目),外键必须反过来存在集合成员那一侧(曲目记录里存唱片的外键),更新时就要面对”怎么知道集合里加了什么、删了什么”这个问题,有三种解法。删除和插入:每次更新前先删掉数据库里和这张唱片相连的全部曲目记录,再把内存里唱片当前持有的全部曲目一次性插入回去——哪怕一条曲目都没真正变过也照删不误,看起来浪费,但逻辑简单、往往反而跑得更快;局限是只有当曲目属于依赖映射(完全归唱片所有、不会被唱片之外的东西引用)时才能这样做。加一个后向指针:让曲目反过来持有一个指向唱片的链接,把关联变成双向——代价是改变了对象模型本身,换来的好处是可以直接套用处理单值域的简单更新技术,不再需要操心集合层面的增删检测。区分对象集:如果前两种都不合适,就只能老老实实做差异对比——要么”通过数据库当前状态区分”(重新从数据库读一份现有集合,和内存里的集合逐一比对,数据库有但内存没有的就删,内存有但数据库没有的就插),要么”通过第一次读取时保存的数据区分”(省一次数据库读取,但如果用了乐观离线锁,可能还是绕不开要通过数据库比对)。此外,向后链接如果是强制的(每条曲目必须归属某张唱片)或链接本身恒定不变(曲目一旦确定就不能换唱片),处理起来都会明显更简单——移除操作就不用单独处理,或者加入永远对应插入、移除永远对应删除。
结构图:
flowchart TB
A["集合外键更新怎么做"]
A --> B["删除+重插入<br/>简单但要求曲目是依赖映射"]
A --> C["加后向指针<br/>变双向关联<br/>换取单值更新的简单性"]
A --> D["区分对象集<br/>数据库当前状态 vs 首次读取快照<br/>逐一比对增删"]
参考来源
- 位置:《企业应用架构模式》第二部分"模式"之"第12章 对象-关系结构模式"之"12.2.1 运行机制"(源文件:_epub-src/OEBPS/Text/000110.html)
- 结论依据:原文说明"一共有三个选择:(1)删除和插入;(2)加入一个后向指针;(3)区分对象集……如果是删除和插入……缺点就是只能在曲目是依赖映射的情况下才可以这么做……加入一个后向指针……这么做改变了对象模型,但是现在你就可以使用处理单值域的简单技术来处理更新操作……如果这两种情况都不是,那就可以进行一次区分",直接支撑本卡结构图。
- 原始内容:如果向后链接是强制的,处理删除操作就容易得多……如果链接是恒定不变的,也就是说不能改变曲目的唱片,这样加入就总意味着插入,移除就总意味着删除。