知识卡片
标识映射保一致性、延迟加载保性能,是两回事
内容
加载对象时最容易踩的坑是把同一条数据库行加载成内存中两个不同的对象——一旦都被更新就会互相覆盖、乱成一团。标识映射解决这个问题:每次从数据库读入一行前,先到标识映射里查一下这行是不是已经加载过,加载过就直接返回已有对象的引用,从而保证同一行数据在内存里永远只对应一个对象。这样做顺带也能省掉一些数据库调用(因为标识映射客观上像一层缓存),但作者特别提醒:标识映射存在的根本目的是保持一致性,不是为了提高性能,不要为了性能收益而误判它的定位。另一个相关但目的不同的问题是:如果领域模型里对象之间层层关联,读取一个对象很容易把大量关联对象也一并从数据库带出来,造成不必要的浪费。延迟加载解决的正是这个问题:让对象持有的关联引用先指向一个占位符而不是真实对象,只有当代码真的通过这个引用去访问关联对象时,才触发一次实际的数据库读取。两者常常被放在一起讨论,容易被误认为是同一件事,但标识映射管的是”同一份数据会不会被加载成多份、导致更新冲突”,延迟加载管的是”要不要现在就把关联数据都拉出来”——目的完全不同,只是恰好经常协同工作(延迟加载触发的真实读取仍然要经过标识映射去重)。
参考来源
- 位置:《企业应用架构模式》第一部分"表述"之"第3章 映射到关系数据库"之"3.2 行为问题"(源文件:_epub-src/OEBPS/Text/000018.html)
- 结论依据:原文说明"为了解决这个问题,可以在标识映射里记录读取的每一行……可能避免一些数据库调用,因为标识映射就像一个数据库高速缓存。不过不要忘了,标识映射的主要目的是保持一致性,而不是提高性能……延迟加载的主要思想是拥有一个对象引用的占位符……当且仅当想要通过链接访问的时候,才会真的去数据库中读取实际的对象",直接支撑本卡结论。
- 原始内容:不过不要忘了,标识映射的主要目的是保持一致性,而不是提高性能……延迟加载的主要思想是拥有一个对象引用的占位符。可以采用几种方法,但它们的共同点都是拥有被修改对象的对象引用,它指向的是一个占位符而不是实际的对象。