关系型数据库映射指南
立即解锁
发布时间: 2025-08-21 02:15:15 阅读量: 1 订阅数: 4 


企业应用架构模式:构建复杂系统的实用指南
### 关系型数据库映射指南
#### 1. 考虑使用 O/R 映射工具
即便无法使用面向对象(OO)数据库,若有领域模型,也应认真考虑购买 O/R 映射工具。构建数据映射器是一项复杂的工作,而工具供应商在该问题上已投入多年精力,商业 O/R 映射工具比手动实现更为复杂精细。虽然工具价格不菲,但需将其与自行编写和维护该层的高昂成本相比较。
在 Java 领域,有类似 JDO 这样尝试提供能与关系型数据库配合使用的 OO 数据库风格层的工具,但目前还难以判断其效果。
即便购买了工具,了解相关模式也很有必要。优秀的 O/R 工具在数据库映射方面提供了多种选项,这些模式有助于理解何时选择不同的方案。不能认为工具能解决所有问题,使用和调整 O/R 工具仍需投入一定的工作。
#### 2. 行为问题
人们谈论 O/R 映射时,通常关注结构方面,即如何将表与对象关联起来。但实际上,最具挑战性的是架构和行为方面。行为问题主要涉及如何让各种对象将自身加载和保存到数据库。
乍一看,这似乎不是大问题,例如客户对象可以有加载和保存方法来完成此任务,使用活动记录模式时这是一种明显的做法。然而,当将大量对象加载到内存并进行修改时,就需要跟踪哪些对象被修改过,并确保将所有修改后的对象写回数据库。随着加载对象数量的增加,这个问题会变得更加复杂,特别是在创建新行并修改其他行时,因为在修改引用这些新行的行之前需要获取新行的键。
在读取和修改对象时,还需确保所处理的数据库状态保持一致。读取对象时,要保证读取操作是隔离的,以免在处理这些对象时其他进程对其进行修改,否则可能导致对象中的数据不一致或无效,这就是并发问题,是一个难以解决的问题。
解决上述两个问题的关键模式是工作单元模式。工作单元会跟踪从数据库读取的所有对象以及以任何方式修改的所有对象,并处理对数据库的更新操作。应用程序程序员只需告诉工作单元进行提交,工作单元会将所有适当的行为按顺序应用到数据库,将复杂的提交处理集中在一处。当与数据库的行为交互变得棘手时,工作单元模式是必不可少的。可以将工作单元视为数据库映射的控制器,没有工作单元时,通常由领域层充当控制器来决定何时读写数据库,而工作单元模式将数据库映射的控制行为提取到了单独的对象中。
加载对象时,要避免重复加载同一个对象。若重复加载,会在内存中产生两个对应于同一数据库行的对象,对它们进行更新会导致混乱。为解决这个问题,需要使用标识映射来记录读取的每一行。每次读取数据时,先检查标识映射,确保数据未被加载过。若数据已加载,则返回其第二个引用,这样可以确保更新操作得到正确协调。标识映射还可作为数据库的缓存,有助于避免数据库调用,但要注意其主要目的是维护正确的标识,而非提高性能。
若使用领域模型,通常会将关联对象一起加载,例如读取订单对象时加载其关联的客户对象。但当许多对象相互关联时,读取任何一个对象都可能从数据库中拉出一个庞大的对象图。为避免这种低效情况,需要减少每次读取的数据量,同时保留在需要时获取更多数据的可能性。懒加载模式通过使用对象引用的占位符来实现这一点。该模式有多种变体,但核心是将对象引用修改为占位符,只有在尝试访问该引用时才从数据库中加载实际对象。在合适的位置使用懒加载模式,可以每次从数据库中获取适量的数据。
#### 3. 数据读取
读取数据时,可以将方法视为封装了 SQL 查询语句的查找器,例如 `find(id)` 或 `findForCustomer(customer)` 方法。若查询语句中有大量不同的子句,这些方法可能会变得难以管理,但这种情况较为少见。
查找器方法的放置位置取决于所使用的接口模式。如果数据库交互类是基于表的(即每个数据库表对应一个类实例),则可以将查找器方法与插入和更新操作结合使用;如果交互类是基于行的(即每个数据库行对应一个交互类),则这种方法不可行。
对于基于行的类,可以将查找操作设为静态方法,但这样会使数据库操作不可替换,即无法使用服务存根来替换数据库进行测试。为避免这个问题,最好使用单独的查找器对象。每个查找器类有多个封装 SQL 查询的方法,执行查询时,查找器对象会返回相应的基于行的对象集合。
使用查找器方法时要注意,它们基于数据库状态而非对象状态。例如,对数据库进行查询以查找俱乐部内的所有人时,内存中添加到俱乐部的人员对象不会被查询到。因此,通常最好在开始时进行查询。
读取数据时,性能问题往往很突出,以下是一些经验法则:
- 尽量一次性拉取多行数据,避免对同一表进行重复查询以获取多行数据。通常,拉取过多数据比拉取过少数据更好(但使用悲观并发控制时要注意锁定过多行的问题)。例如,需要通过领域模型中的主键获取 50 个人,但只能构造一个返回 200 个人的查询,然后通过进一步的逻辑筛选出所需的 50 个人,此时使用一个返回不必要行的查询通常比执行 50 个单独的查询更好。
- 使用连接操作,以便通过单个查询拉取多个表的数据。这样得到的记录集可能看起来有些奇怪,但可以显著提高速度。在这种情况下,可能会有一个包含多个连接表数据
0
0
复制全文
相关推荐










