工作单元模式:数据库事务管理的有效方案
立即解锁
发布时间: 2025-08-21 02:15:20 阅读量: 1 订阅数: 4 


企业应用架构模式:构建复杂系统的实用指南
### 工作单元模式:数据库事务管理的有效方案
#### 1. 工作单元模式概述
在进行数据库数据的读写操作时,跟踪数据的变化至关重要。若不跟踪,修改的数据将无法写回数据库,同时还需处理新对象的插入和旧对象的删除。若每次对象模型的改变都直接更新数据库,会导致大量小的数据库调用,效率低下,且在跨多个请求的业务事务中不切实际。若要避免不一致的读取,还需跟踪已读取的对象。
工作单元(Unit of Work)可以跟踪业务事务中所有可能影响数据库的操作。当事务完成时,它会确定需要对数据库进行的所有更改。其核心功能包括维护受业务事务影响的对象列表,协调更改的写入以及解决并发问题。
#### 2. 工作单元的工作原理
工作单元是一个对象,用于跟踪对象的创建、更新和删除操作。当开始可能影响数据库的操作时,创建一个工作单元来跟踪这些变化。每次创建、更改或删除对象时,都要告知工作单元。还可以让工作单元知晓已读取的对象,以便在业务事务期间检查是否存在不一致的读取。
工作单元提供了以下几个重要方法:
- `registerNew(object)`:注册新对象。
- `registerDirty (object)`:注册已更改的对象。
- `registerClean(object)`:注册未更改的对象。
- `registerDeleted(object)`:注册已删除的对象。
- `commit()`:提交更改到数据库。
在提交时,工作单元会打开一个事务,进行并发检查(使用悲观离线锁或乐观离线锁),并将更改写入数据库。应用程序开发人员无需显式调用数据库更新方法,从而无需跟踪哪些对象已更改,也不必担心引用完整性对操作顺序的影响。
#### 3. 对象注册方式
工作单元需要知道要跟踪哪些对象,有两种注册方式:
- **调用者注册**:对象的使用者必须记得将对象的更改注册到工作单元中。未注册的对象在提交时不会被写入数据库。这种方式虽然允许进行内存中的更改而不写入数据库,但容易因遗忘而导致问题,且会带来更多的混乱。
```mermaid
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(client):::process -->|select| B(database):::process
A -->|new| C(a unit of work):::process
B -->|a customer| A
A -->|set credit limit| A
A -->|register dirty| C
C -->|commit| B
B -->|save| B
B -->|update| B
```
- **对象注册**:将注册方法放在对象的方法中。从数据库加载对象时将其注册为未更改,设置对象属性时将其注册为已更改。这种方式减轻了调用者的负担,但开发人员需要记得在正确的位置添加注册调用。
```mermaid
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(client):::process -->|new| B(a customer):::process
A -->|select| C(database):::process
A -->|new| D(a unit of work):::process
C -->|a customer| B
B -->|register clean| D
B -->|set credit limit| B
B -->|register dirty| D
D -->|commit| C
C -->|save| C
C -->|update| C
```
#### 4. 其他相关技术和应用场景
- **代码生成和面向方面编程**:由于对象注册需要开发人员手动添加注册调用,容易出错。代码生成可以自动生成这些调用,但需要能清晰区分生成代码和非生成代码。面向方面编程更适合解决这个问题,它可以更干净地处理源代码。
- **工作单元控制器**:如TOPLink产品使用的方式,工作单元处理所有数据库读取操作,并在读取时注册未更改的对象。在提交时,通过比较对象的副本,实现仅更新实际更改的字段,避免了在领域对象中进行注册调用。也可以采用混合方法,仅对已更改的对象进行复制,以减少开销。
- **对象创建时的调用者注册**:在对象创建时,调用者注册有其特殊用途。例如在测试领域对象时,创建的对象可能只是临时的,调用者注册可以明确这种情况。也可以提供不向工作单元注册的临时构造函数,或使用特殊的工作单元,在提交时不做任何操作。
- **更新顺序和死锁处理**:当数据库使用引用完整性时,工作单元可以帮助确定更新顺序。大多数情况下,可让数据库在事务提交时检查引用完整性。若无法实现,工作单元可以根据外键依赖关系确定写入顺序。在大型应用中,可使用元数据来确定顺序。此外,使用相同的表编辑顺序可以减少死锁的风险,工作单元是保存固定表写入顺序的理想位置。
- **对象查找工作单元**:对象需要能够找到当前的工作单元。可以使用线程作用域的注册表,也可以在方法调用或对象创建时传递工作单元。但要确保一个工作单元不会被多个线程同时访问。
- **批量更新**:工作单元适合处理批量更新,将多个SQL命令作为一个单元发送,减少远程调用次数。不同环境对批量更新的支持不同,如JDBC提供了批量处理单个语句的功能,若没有该功能,可通过构建包含多个SQL语句的字符串来模拟。
- **.NET实现**:在.NET中,工作单元由断开连接的数据集实现。它与传统的工作单元模式略有不同,.NET将数据从数据库读取到数据集中,数据集是类似于数据库表、行和列的对象集合。每个数据行有版本(当前、原始、提议)和状态(未更改、添加、删除、修改)的概念,便于将更改写回数据库。
#### 5. 何时使用工作单元模式
工作单元模式主要解决的问题是跟踪操作过的对象,以便将内存中的数据与数据库同步。若能在一个系统事务内完成所有工作,只需关注更改的对象。虽然工作单元通常是最佳选择,但也有其他替代方案:
- **显式保存对象**:每次更改对象时显式保存,会导致过多的数据库调用。
- **使用变量跟踪**:使用变量跟踪更改的对象,但在对象较多时难以管理,在领域模型中使用更困难。
- **使用脏标志**:为每个对象设置脏标志,事务结束时找出所有脏对象并写入数据库。但在复杂的对象网络中,查找脏对象较为困难。
工作单元模式的优势在于将所有跟踪信息集中管理,使用后无需过多关注数据变化的跟踪。此外,它为处理复杂情况(如跨多个系统事务的业务事务)提供了坚实的基础。
#### 6. Java示例:使用对象注册的工作单元
以下是一个使用Java实现的工作单元示例,它可以跟踪业务事务中的所有更改,并
0
0
复制全文
相关推荐










