谈谈实体的 ID 与“键”

本文探讨了实体的领域ID是否应该映射为数据库的自然键,以及何时使用代理键。强调实体ID通常需要被最终用户看到,自然键在大多数情况下应优先考虑。代理键的使用应在特定优化需求时考虑,而设计领域模型时应关注领域ID,避免过度依赖代理键。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

“实体”几乎是每个开发人员耳熟能详的概念。特别是对于使用过 ORM 框架的开发人员,当你提到“实体”,他们可能马上就会想到“就是需要映射为数据表(Table)的那些对象嘛”。

实体也是领域驱动设计(DDD)的战术层面最重要的概念之一(个人以为,DDD 战术层面最重要的三个概念是聚合、实体以及值对象)。由于大家对“实体”如此熟悉,所以要理解下面的讨论其实并不需要了解 DDD。

即使是不了解 DDD 的开发人员都“公认”实体是指这一类对象:拥有标识符(简称 ID),不管对象的状态如何变化,它的 ID 总是不变的。我们可以把这个 ID 称为实体的领域 ID。

比如说,我们的银行账户(Account),总是有一个编号(账号)的。我们存钱、取钱,账户里面的钱会发生变化,但是账号不变。我们通过这个账号,能够查询到账户的余额。所以,我们可以把银行账户建模为一个实体,选择它的编号作为这个实体的 ID。

问题

我相信很多人都思考过类似的问题:

实体的领域 ID 是不是应该映射到关系模型(数据库)的自然键?如果一个实体的 ID 已经是“自然键”了,那么与之对应的关系数据库的表(Table) 中还有必要再引入这个 ID 之外的代理键吗?

还有,如果领域 ID 可以是代理键,那么它什么时候应该是代理键?

我们可能都见过这样的软件系统:开发人员会不分青红皂白地给每个表(实体)设计一个代理主键。那么,在代码中这样重度地使用代理键是合理的做法吗?

如果一个实体需要被其他实体引用的时候,其他实体是不是应该尽可能统一地通过持有它的领域 ID 的值来引用(指向)它?

自然键与代理键

在上面的问题中,出现了自然键和代理键的概念。考虑到代理键是和自然键是相对的概念,我们先搞清楚什么是自然键(Natural Key)就可以了。那么,什么是自然键?根据维基百科:

In relational model database design, a natural key is a key that is formed of attributes that already exist in the real world. For example, a USA citizen's social security number could be used as a natural key.

In other words, a natural key is a candidate key that has a logical relationship to the attributes within that row. A natural key is sometimes called domain key.

中文翻译过来就是:

在关系模型数据库设计中,自然键是指由现实世界中已经存在的属性所构成的“键”。举个例子,美国公民的社会保险号码可以用作自然键。换句话来说,自然键是和那一“行”中的属性存在逻辑关系的候选键。自然键有时候也被称为领域键。

根据这个定义,自然键有时候也被称为领域键——领域键和领域 ID,啊哈,称呼已经很接近了不是吗?

我们看到,这个定义还依赖于另外一个概念:现实世界(the real world)。那么,什么是现实世界?如果这个概念没有定义,那么自然键的概念还是“不清不楚”的。

提示

虽然在讨论

<think>嗯,用户让我谈谈对进程管理的理解。首先,我得明确进程管理在操作系统中的角色。进程是程序执行的实例,对吧?那操作系统怎么管理这些进程呢?可能需要从进程的创建、调度、同步、通信和终止这几个方面入手。 进程的生命周期应该包括创建、就绪、运行、阻塞和终止这些状态。用户可能想知道进程是怎么在这些状态之间转换的,比如通过什么事件触发状态变化。比如,当进程等待I/O操作时,会从运行态转到阻塞态,完成后再回到就绪态。 然后是进程调度,这部分可能涉及调度算法。比如先来先服务、短作业优先、轮转调度、优先级调度这些。需要解释每种算法的优缺点,以及适用场景。比如实时系统可能用优先级调度,而交互式系统可能用轮转调度保证响应时间。 进程同步和通信也很重要。多个进程访问共享资源时会出现竞争条件,所以需要同步机制,比如信号量、互斥锁。进程间通信的方式有管道、消息队列、共享内存、套接字等。这些机制的区别和适用情况可能需要说明。 还有进程控制块(PCB),它是操作系统管理进程的关数据结构,存储进程的状态、寄存器、PID等信息。用户可能对PCB的作用不太清楚,需要解释清楚。 可能还需要提到多道程序设计如何提高CPU利用率,以及现代操作系统中的多线程和进程的关系。比如线程是轻量级的进程,共享同一进程的资源,但调度更高效。 用户可能对进程和程序的区别有疑问,所以应该明确进程是动态的执行过程,而程序是静态的代码。此外,守护进程、僵尸进程、孤儿进程这些概念也可能需要简要说明。 最后,要确保结构清晰,分点回答,用例子帮助理解,比如用生产者-消费者问题说明同步机制。同时注意使用正确的中文术语和LaTeX格式,比如调度算法名称用$...$包裹,独立公式如状态转换图用$$...$$。</think>### 对进程管理的理解(分步骤说明) #### 一、进程的定义核心概念 1. **进程的本质** 进程是**程序的一次执行实例**,包含代码、数据、堆栈、寄存器状态和系统资源(如打开的文件)。 - 程序的区别:程序是静态的代码文件,进程是动态的执行实体(例如:$程序=菜谱$,$进程=按菜谱烹饪的过程$)。 2. **进程控制块(PCB)** 操作系统通过**PCB(Process Control Block)** 管理进程,存储以下信息: - 进程ID(PID) - 进程状态(运行/就绪/阻塞等) - 程序计数器(PC) - CPU寄存器值 - 内存分配表 - I/O状态 #### 二、进程生命周期状态转换 1. **进程的5种基本状态** - **新建(New)**:进程被创建 - **就绪(Ready)**:等待CPU分配 - **运行(Running)**:占用CPU执行 - **阻塞(Blocked)**:等待I/O等事件 - **终止(Terminated)**:执行结束 2. **状态转换示例** $$ \text{新建} \xrightarrow{\text{分配资源}} \text{就绪} \xrightarrow{\text{调度}} \text{运行} \xrightarrow{\text{I/O请求}} \text{阻塞} \xrightarrow{\text{事件完成}} \text{就绪} $$ #### 三、进程调度算法 1. **调度目标** 提高CPU利用率、减少响应时间、保证公平性。 2. **经典算法对比** | 算法类型 | 特点 | 公式示例(平均等待时间) | |------------------|-------------------------------|--------------------------| | 先来先服务(FCFS) | 非抢占,适合长作业 | $W_{\text{avg}} = \frac{\sum (完成时间 - 到达时间)}{n}$ | | 短作业优先(SJF) | 最小化平均等待时间 | 通过预测作业长度排序 | | 时间片轮转(RR) | 公平性高,适合交互式系统 | 时间片大小影响吞吐量 | #### 四、进程同步通信 1. **同步问题示例:生产者-消费者** - **问题描述**:共享缓冲区需互斥访问 - **解决方案**:使用信号量(Semaphore) ``` semaphore mutex = 1; // 互斥锁 semaphore empty = N; // 空缓冲区数量 semaphore full = 0; // 满缓冲区数量 ``` 2. **进程通信(IPC)方式** - **共享内存**:高速但需同步 - **消息传递**:通过系统调用(如管道、Socket) - **远程过程调用(RPC)**:跨网络通信 #### 五、现代扩展挑战 1. **线程进程的关系** - 线程是轻量级进程,共享同一进程的资源(如内存空间)。 - 多线程提高并发性,但需处理线程安全问题(例如:$竞态条件$)。 2. **容器化技术的影响** 容器(如Docker)通过**命名空间(Namespace)** 和**控制组(Cgroup)** 实现进程隔离,优化资源管理。 --- ### 总结 进程管理是操作系统的核心功能,需协调: 1. 资源分配(CPU、内存) 2. 状态监控调度 3. 同步通信机制 其设计直接影响系统性能(如吞吐量$T = \frac{\text{完成任务数}}{\text{时间}}$)和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值