提交 6c822ae2 编写于 作者: W wizardforcel

2019-08-29 20:47:21

上级 9c2b5410
......@@ -8,22 +8,23 @@
数据库未范式时会发生三种类型的异常。这些是 - 插入,更新和删除异常。我们举一个例子来理解这一点。
**示例**:假设制造公司将员工详细信息存储在名为 employee 的表中,该表具有四个属性:emp_id 用于存储员工的 id,emp_name 用于存储员工的姓名,emp_address 用于存储员工的地址,emp_dept 用于存储部门详细信息员工的工作方式。在某些时候,表看起来像这样:
**示例**:假设制造公司将员工详细信息存储在名为`employee`的表中,该表具有四个属性:`emp_id`用于存储员工的 id,`emp_name`用于存储员工的姓名,`emp_address`用于存储员工的地址,`emp_dept`用于存储部门详细信息员工的工作方式。在某些时候,表看起来像这样:
| EMP_ID | EMP_NAME | emp_address | 删除 emp_dept |
| 101 | 干草堆 | 新德里 | D001 |
| `emp_id` | `emp_name` | `emp_address` | `emp_dept` |
| --- | --- | --- | --- |
| 101 | Rick | Delhi | D001 |
| 101 | Rick | Delhi | D002 |
| 123 | 劣质煤 | 阿格拉 | D890 |
| 166 | 格伦 | 奈 | D900 |
| 123 | Maggie | Agra | D890 |
| 166 | Glenn | Chennai | D900 |
| 166 | Glenn | Chennai | D004 |
上表未范式。我们将看到当表未范式时我们面临的问题。
**更新异常**:在上表中,员工 Rick 有两行,因为他属于公司的两个部门。如果我们想要更新 Rick 的地址,那么我们必须在两行中更新相同的内容,否则数据将变得不一致。如果不知何故,正确的地址在一个部门更新,但在其他部门没有更新,那么根据数据库,Rick 将有两个不同的地址,这是不正确的,会导致数据不一致。
**插入异常**:假设一名新员工加入正在接受培训并且当前未分配到任何部门的公司,那么如果 emp_dept 字段不允许空值,我们将无法将数据插入表中。
**插入异常**:假设一名新员工加入正在接受培训并且当前未分配到任何部门的公司,那么如果`emp_dept`字段不允许空值,我们将无法将数据插入表中。
**删除异常**:假设,如果公司关闭部门 D890 的某个时间点,那么删除具有 emp_dept 为 D890 的行也会删除员工 Maggie 的信息,因为她只被分配给该部门。
**删除异常**:假设,如果公司关闭部门 D890 的某个时间点,那么删除具有`emp_dept`为 D890 的行也会删除员工 Maggie 的信息,因为她只被分配给该部门。
为了克服这些异常,我们需要范式数据。在下一节中,我们将讨论范式。
......@@ -34,7 +35,7 @@
* 第一范式(1NF)
* 第二范式(2NF)
* 第三范式(3NF)
* 博伊斯& Codd 普通形式(BCNF)
* Boyce Codd 范式(BCNF)
## 第一范式(1NF)
......@@ -42,19 +43,21 @@
**示例**:假设公司想要存储其员工的姓名和联系方式。它创建一个如下所示的表:
| emp_id | emp_name | emp_address | emp_mobile |
| 101 | 赫歇尔 | 新德里 | 8912312390 |
| 102 | 乔恩 | 坎普尔 | 88121212129900012222 |
| 103 | 罗恩 | Chennai | 7778881212 |
| 104 | 莱斯特 | 班加罗尔 | 99900001238123450987 |
| `emp_id` | `emp_name` | `emp_address` | `emp_mobile` |
| --- | --- | --- | --- |
| 101 | Herschel | New Delhi | 8912312390 |
| 102 | Jon | Kanpur | 88121212129900012222 |
| 103 | Ron | Chennai | 7778881212 |
| 104 | Lester | Bangalore | 99900001238123450987 |
两名员工(Jon& Lester)有两个手机号码,因此公司将它们存储在您在上表中看到的相同字段中。
该表是**不在 1NF** 中,因为规则说“表的每个属性必须具有原子(单个)值”,员工的 emp_mobile 值为 Jon&莱斯特违反了这条规则。
该表是**不在 1NF** 中,因为规则说“表的每个属性必须具有原子(单个)值”,员工的`emp_mobile`值为`Jon & Lester`违反了这条规则。
为了使表符合 1NF,我们应该有这样的数据:
| emp_id | emp_name | emp_address | emp_mobile |
| `emp_id` | `emp_name` | `emp_address` | `emp_mobile` |
| --- | --- | --- | --- |
| 101 | Herschel | New Delhi | 8912312390 |
| 102 | Jon | Kanpur | 8812121212 |
| 102 | Jon | Kanpur | 9900012222 |
......@@ -67,35 +70,40 @@
如果以下两个条件成立,则表示在 2NF 中:
* 表为 1NF(第一范式)
* 没有非素数属性取决于表的任何候选键的适当子集。
* 没有非属性取决于表的任何候选键的适当子集。
不属于任何候选键的属性称为非素数属性。
不属于任何候选键的属性称为非属性。
**示例**:假设学校想要存储教师的数据和他们教授的科目。他们创建了一个如下所示的表:由于教师可以​​教授多个科目,因此该表可以为同一位教师设置多行。
| teacher_id | 学科 | teacher_age |
| 111 | 数学 | 38 |
| 111 | 物理 | 38 |
| 222 | 生物学 | 38 |
| `teacher_id` | `subject` | `teacher_age` |
| --- | --- | --- |
| 111 | Maths | 38 |
| 111 | Physics | 38 |
| 222 | Biology | 38 |
| 333 | Physics | 40 |
| 333 | 化学 | 40 |
| 333 | Chemistry | 40 |
**候选键**`{teacher_id, subject}`
**候选键**:{teacher_id,subject}
**非素数属性**:teacher_age
**非主属性**`teacher_age`
该表在 1 NF 中,因为每个属性都有原子值。但是,它不在 2NF 中,因为非素数属性 teacher_age 仅依赖于 teacher_id,它是候选键的适当子集。这违反了 2NF 的规则,因为规则说“**没有**非素数属性依赖于表的任何候选键的正确子集”。
该表在 1 NF 中,因为每个属性都有原子值。但是,它不在 2NF 中,因为非主属性`teacher_age`仅依赖于`teacher_id`,它是候选键的适当子集。这违反了 2NF 的规则,因为规则说“**没有**非主属性依赖于表的任何候选键的正确子集”。
为了使表符合 2NF,我们可以在两个表中打破它:
**teacher_details 表:**
| teacher_id | teacher_age |
**`teacher_details`表:**
| `teacher_id` | `teacher_age` |
| --- | --- |
| 111 | 38 |
| 222 | 38 |
| 333 | 40 |
**teacher_subject 表:**
**`teacher_subject `表:**
| teacher_id | subject |
| `teacher_id` | `subject` |
| --- | --- |
| 111 | Maths |
| 111 | Physics |
| 222 | Biology |
......@@ -111,44 +119,49 @@
* 表必须是 2NF
* [应删除任何超键上非主要属性的传递函数依赖](https://beginnersbook.com/2015/04/transitive-dependency-in-dbms/)
不属于任何[候选键](https://beginnersbook.com/2015/04/candidate-key-in-dbms/)的属性称为非素数属性。
不属于任何[候选键](https://beginnersbook.com/2015/04/candidate-key-in-dbms/)的属性称为非属性。
换句话说,3NF 可以这样解释:如果表在 2NF 中,则表在 3NF 中,并且对于每个函数依赖性 X-> Y 至少满足下列条件之一:
换句话说,3NF 可以这样解释:如果表在 2NF 中,则表在 3NF 中,并且对于每个函数依赖`X -> Y`至少满足下列条件之一:
* X 是表的[超键](https://beginnersbook.com/2015/04/super-key-in-dbms/)
* Y 是表的主要属性
* `X`是表的[超键](https://beginnersbook.com/2015/04/super-key-in-dbms/)
* `Y`是表的主要属性
作为候选键之一的一部分的属性称为主要属性。
**示例**:假设公司想要存储每个员工的完整地址,他们会创建一个名为 employee_details 的表,如下所示:
**示例**:假设公司想要存储每个员工的完整地址,他们会创建一个名为`employee_details`的表,如下所示:
| `emp_id` | `emp_name` | `emp_zip` | `emp_state` | `emp_city` | `emp_district` |
| --- | --- | --- | --- | --- |
| 1001 | John | 282005 | UP | Agra | Dayal Bagh |
| 1002 | Ajeet | 222008 | TN | Chennai | M-City |
| 1006 | Lora | 282007 | TN | Chennai | Urrapakkam |
| 1101 | Lilly | 292008 | UK | Pauri | Bhagwan |
| 1201 | Steve | 222999 | MP | Gwalior | Ratan |
| emp_id | emp_name | emp_zip | emp_state | emp_city | emp_district |
| 1001 | 约翰 | 282005 | UP | Agra | Dayal Bagh |
| 1002 | Ajeet | 222008 | TN | Chennai | M-市 |
| 1006 | 洛拉 | 282007 | TN | Chennai | 乌拉帕卡姆 |
| 1101 | 礼来公司 | 292008 | 联合王国 | Pauri | 巴格 |
| 1201 | 史蒂夫 | 222999 | MP | 瓜廖尔 | 拉坦 |
**超键**`{emp_id}``{emp_id, emp_name}``{emp_id, emp_name, emp_zip}`...等
**超键**:{emp_id},{emp_id,emp_name},{emp_id,emp_name,emp_zip} ...等
**候选键**:{emp_id}
**非素数属性**:除 emp_id 之外的所有属性都是非素数,因为它们不是任何候选键的一部分。
**候选键**`{emp_id}`
在这里,emp_state,emp_city& emp_district 依赖于 emp_zip。并且,emp_zip 依赖于 emp_id,这使得非素数属性(emp_state,emp_city& emp_district)可传递地依赖于超键(emp_id)。这违反了 3NF 的规则。
**非主属性**:除`emp_id`之外的所有属性都是非主,因为它们不是任何候选键的一部分。
在这里,`emp_state``emp_city``emp_district`依赖于`emp_zip`。并且,`emp_zip`依赖于`emp_id`,这使得非主属性(`emp_state``emp_city``emp_district`)可传递地依赖于超键(`emp_id`)。这违反了 3NF 的规则。
要使此表符合 3NF,我们必须将表拆分为两个表以删除传递依赖项:
**员工表:**
| emp_id | emp_name | emp_zip |
| `emp_id` | `emp_name` | `emp_zip` |
| --- | --- | --- |
| 1001 | John | 282005 |
| 1002 | Ajeet | 222008 |
| 1006 | Lora | 282007 |
| 1101 | Lilly | 292008 |
| 1201 | Steve | 222999 |
**employee_zip 表:**
**`employee_zip`表:**
| emp_zip | emp_state | emp_city | emp_district |
| `emp_zip` | `emp_state` | `emp_city` | `emp_district` |
| --- | --- | --- | --- |
| 282005 | UP | Agra | Dayal Bagh |
| 222008 | TN | Chennai | M-City |
| 282007 | TN | Chennai | Urrapakkam |
......@@ -157,54 +170,62 @@
## Boyce Codd 范式(BCNF)
它是 3NF 的高级版本,这也是它被称为 3.5NF 的原因。 BCNF 比 3NF 更严格。如果表是 3NF,则表符合 BCNF,对于每个[函数依赖](https://beginnersbook.com/2015/04/functional-dependency-in-dbms/) X-> Y,X 应该是表的超键。
它是 3NF 的高级版本,这也是它被称为 3.5NF 的原因。 BCNF 比 3NF 更严格。如果表是 3NF,则表符合 BCNF,对于每个[函数依赖](https://beginnersbook.com/2015/04/functional-dependency-in-dbms/)`X -> Y``X`应该是表的超键。
**示例**:假设有一家公司,员工在**多个部门工作**。他们存储这样的数据:
| emp_id | emp_nationality | emp_dept | dept_type | dept_no_of_emp |
| 1001 | 奥 | 生产和计划 | D001 | 200 |
| 1001 | Austrian | 商店 | D001 | 250 |
| 1002 | 美国 | 设计和技术支持 | D134 | 100 |
| 1002 | American | 采购部门 | D134 | 600 |
| `emp_id` | `emp_nationality` | `emp_dept` | `dept_type` | `dept_no_of_emp` |
| --- | --- | --- | --- | --- |
| 1001 | Austrian | Production and planning | D001 | 200 |
| 1001 | Austrian | stores | D001 | 250 |
| 1002 | American | design and technical support | D134 | 100 |
| 1002 | American | Purchasing department | D134 | 600 |
**上表**中的函数依赖:
**上表**中的函数依赖性:
emp_id - > emp_nationality
emp_dept - > {dept_type,dept_no_of_emp}
+ `emp_id -> emp_nationality`
+ `emp_dept -> {dept_type,dept_no_of_emp}`
**候选键**{emp_id,emp_dept}
**候选键**`{emp_id, emp_dept}`
该表不在 BCNF 中,因为 emp_id 和 emp_dept 都不是键。
该表不在 BCNF 中,因为`emp_id``emp_dept`都不是键。
为了使表符合 BCNF,我们可以在三个表中打破这样的表:
**emp_nationality 表:**
| emp_id | emp_nationality |
**`emp_nationality`表:**
| `emp_id` | `emp_nationality` |
| --- | --- |
| 1001 | Austrian |
| 1002 | American |
**emp_dept 表:**
**`emp_dept`表:**
| emp_dept | dept_type | dept_no_of_emp |
| `emp_dept` | `dept_type` | `dept_no_of_emp` |
| --- | --- | --- |
| Production and planning | D001 | 200 |
| stores | D001 | 250 |
| design and technical support | D134 | 100 |
| Purchasing department | D134 | 600 |
**emp_dept_mapping 表:**
**`emp_dept_mapping`表:**
| emp_id | emp_dept |
| `emp_id` | `emp_dept` |
| --- | --- |
| 1001 | Production and planning |
| 1001 | stores |
| 1002 | design and technical support |
| 1002 | Purchasing department |
**函数依赖性**
emp_id - > emp_nationality
emp_dept - > {dept_type,dept_no_of_emp}
**函数依赖**
+ `emp_id -> emp_nationality`
+ `emp_dept -> {dept_type, dept_no_of_emp}`
**候选键**
第一个表:emp_id
第二个表:emp_dept
第三个表:{emp_id,emp_dept}
现在这是在 BCNF 中,因为在函数依赖性中左侧部分是关键。
\ No newline at end of file
+ 第一个表:`emp_id`
+ 第二个表:`emp_dept`
+ 第三个表:`{emp_id, emp_dept}`
现在这是在 BCNF 中,因为在函数依赖中左侧部分是关键。
\ No newline at end of file
......@@ -6,12 +6,12 @@
## 简单事务示例
1.阅读您的账户余额
2.扣除余额中的金额
3.将余额写入您的账户
4.读取您朋友的账户余额
5.将金额添加到他的账户余额
6.将新的更新余额写入其账户
1. 阅读您的账户余额
2. 扣除余额中的金额
3. 将余额写入您的账户
4. 读取您朋友的账户余额
5. 将金额添加到他的账户余额
6. 将新的更新余额写入其账户
这整组操作可以称为事务。虽然我已在上面的示例中向您展示了读取,写入和更新操作,但事务可以具有读取,写入,插入,更新,删除等操作。
......@@ -19,16 +19,16 @@
假设您的账户是 A 而您朋友的账户是 B,您要从 A 转移 10000 到 B,事务的步骤是:
```
1\. R(A);
2\. A = A - 10000;
3\. W(A);
4\. R(B);
5\. B = B + 10000;
6\. W(B);
1. R(A);
2. A = A - 10000;
3. W(A);
4. R(B);
5. B = B + 10000;
6. W(B);
```
在上述事务中 **R** 是指**读操作****W** 是指**写操作**
在上述事务中 **`R`** 是指**读操作****`W`** 是指**写操作**
## 操作之间的事务失败
......
......@@ -4,7 +4,7 @@
为了确保事务期间数据的完整性(**事务是一个更新各种数据项的程序单元,请在此处阅读更多相关信息**),数据库系统维护以下属性。这些属性被广泛称为 ACID 属性:
* **Atomicity** :此属性确保事务的所有操作都反映在数据库中或不反映。让我们举一个银行系统的例子来理解这一点:假设账户 **A** 的余额为 400 美元& **B** 有 700 美元。账号 **A** 正在向账户 **B** 转账 100 美元。这是一个有两个操作的事务 a)从 A 的余额中扣除 100 美元 b)创建 100 美元到 B 的余额。假设第一次操作成功通过而第二次失败,在这种情况下 A 的余额为 300 $而 B 则为 700 $而不是 800 $。这在银行系统中是不可接受的。如果事务在没有执行任何操作的情况下失败,或者它应该处理这两个操作。原子性属性确保了这一点。
* **原子性** :此属性确保事务的所有操作都反映在数据库中或不反映。让我们举一个银行系统的例子来理解这一点:假设账户 **A** 的余额为 400 美元& **B** 有 700 美元。账号 **A** 正在向账户 **B** 转账 100 美元。这是一个有两个操作的事务 a)从 A 的余额中扣除 100 美元 b)创建 100 美元到 B 的余额。假设第一次操作成功通过而第二次失败,在这种情况下 A 的余额为 300 $而 B 则为 700 $而不是 800 $。这在银行系统中是不可接受的。如果事务在没有执行任何操作的情况下失败,或者它应该处理这两个操作。原子性属性确保了这一点。
* **一致性**:为了保持数据库的一致性,事务的执行应该孤立地进行(这意味着当事务已经运行时,不应该同时运行其他事务)。例如,账户 A 的余额为 400 美元,它将 100 美元转账到账户 B& C 两者。所以我们在这里有两笔事务。假设这些事务同时运行,两笔事务均为 400 美元余额,在这种情况下,A 的最终余额为 300 美元而不是 200 美元。这是错的。如果事务是在隔离的情况下运行,那么第一笔事务成功后,第二笔事务就会读取正确的余额 300 美元(在扣除 100 美元之前)。
* **隔离**:对于每对事务,只有当另一个事务完成执行时,才会开始执行一个事务。我已经在上面的 Consistency 属性中讨论过 Isolation 的例子。
* **隔离**:对于每对事务,只有当另一个事务完成执行时,才会开始执行一个事务。我已经在上面的一致性属性中讨论过隔离的例子。
* **持久性**:一旦事务成功完成,即使系统出现故障,它对数据库所做的更改也应该是永久性的。数据库系统的恢复管理组件可确保事务的持久性。
\ No newline at end of file
# DBMS 计划和计划类型
# DBMS 调度和调度类型
> 原文: [https://beginnersbook.com/2018/12/dbms-schedules/](https://beginnersbook.com/2018/12/dbms-schedules/)
我们知道[事务](https://beginnersbook.com/2017/09/transaction-management-in-dbms/)是一组指令,这些指令在数据库上执行操作。当多个事务同时运行时,需要有一个执行操作的序列,因为一次只能对数据库执行一个操作。这一系列操作称为 **Schedule**
我们知道[事务](https://beginnersbook.com/2017/09/transaction-management-in-dbms/)是一组指令,这些指令在数据库上执行操作。当多个事务同时运行时,需要有一个执行操作的序列,因为一次只能对数据库执行一个操作。这一系列操作称为 **调度**
让我们举个例子来了解 DBMS 中的计划是什么。
让我们举个例子来了解 DBMS 中的调度是什么。
## DBMS 计划示例
## DBMS 调度示例
以下操作顺序是计划。这里我们有两个事务 T1& T2 同时运行。
以下操作顺序是调度。这里我们有两个事务`T1``T2`同时运行。
计划确定将在数据库上执行的操作的确切顺序。在这个例子中,事务 T1 的所有指令都在事务 T2 的指令之前执行,但是这并不总是必要的,我们可以有各种类型的调度,我们将在本文中讨论。
调度确定将在数据库上执行的操作的确切顺序。在这个例子中,事务`T1`的所有指令都在事务`T2`的指令之前执行,但是这并不总是必要的,我们可以有各种类型的调度,我们将在本文中讨论。
```
T1 T2
......@@ -23,19 +23,20 @@ R(Y)
W(Y)
```
## DBMS 中的计划类型
## DBMS 中的调度类型
我们在 DBMS 中有各种类型的调度。让我们逐一讨论它们。
我们在 DBMS 中有各种类型的计划。让我们逐一讨论它们。
![Types of Schedules in DBMS](img/62624309060fdaeea5bf68abda481e50.jpg)
### 串行计划
### 串行调度
**串行调度**中,在开始执行另一个事务之前完全执行事务。换句话说,您可以说在串行调度中,事务在当前正在运行的事务完成执行之前不会开始执行。这种类型的事务执行也称为**非交错**执行。我们上面看到的例子是连续计划
**串行调度**中,在开始执行另一个事务之前完全执行事务。换句话说,您可以说在串行调度中,事务在当前正在运行的事务完成执行之前不会开始执行。这种类型的事务执行也称为**非交错**执行。我们上面看到的例子是连续调度
让我们再看一个例子。
**串行调度示例**
这里 R 表示读操作,W 表示写操作。在此示例中,事务 T2 在事务 T1 完成之前不会开始执行。
这里`R`表示读操作,`W`表示写操作。在此示例中,事务`T2`在事务`T1`完成之前不会开始执行。
```
T1 T2
......@@ -50,14 +51,15 @@ commit
commit
```
### 严格的计划
### 严格的调度
在严格计划中,如果事务的写入操作先于另一个事务的冲突操作(读取或写入操作),则此类事务的提交或中止操作也应该在其他事务的冲突操作之前。
在严格调度中,如果事务的写入操作先于另一个事务的冲突操作(读取或写入操作),则此类事务的提交或中止操作也应该在其他事务的冲突操作之前。
让我们举个例子。
**严格计划示例**
假设我们有两个事务 Ta 和 Tb。事务 Ta 的写入操作在事务 Tb 的读取或写入操作之前,因此事务 Ta 的提交或中止操作也应该在读取或写入 Tb 之前。
**严格调度示例**
假设我们有两个事务`Ta``Tb`。事务`Ta`的写入操作在事务`Tb`的读取或写入操作之前,因此事务`Ta`的提交或中止操作也应该在读取或写入`Tb`之前。
```
Ta Tb
......@@ -71,14 +73,14 @@ commit
commit
```
这里,Ta 的写操作 W(X)在 Tb 的冲突操作(读或写操作)之前,因此 Tb 的冲突操作必须等待 Ta 的提交操作。
这里,`Ta`的写操作`W(X)``Tb`的冲突操作(读或写操作)之前,因此`Tb`的冲突操作必须等待`Ta`的提交操作。
### 无级联计划
### 无级联调度
Cascadeless Schedule 中,如果事务要对某个值执行读操作,则必须等到执行写入该值的事务提交。
无级联调度中,如果事务要对某个值执行读操作,则必须等到执行写入该值的事务提交。
**Cascadeless Schedule 示例**
例如,假设我们有两个事务 Ta 和 Tb。 Tb 将在 Ta 的 W(X)之后读取值 X,然后 Tb 必须在读取 X 之前等待事务 Ta 的提交操作。
**无级联调度示例**
例如,假设我们有两个事务`Ta``Tb``Tb`将在`Ta``W(X)`之后读取值`X`,然后`Tb`必须在读取`X`之前等待事务`Ta`的提交操作。
```
Ta Tb
......@@ -92,12 +94,13 @@ commit
commit
```
### 可恢复的计划
### 可恢复的调度
在可恢复计划中,如果事务正在读取已由某个其他事务更新的值,则此事务只能在提交正在更新值的其他事务之后提交。
在可恢复调度中,如果事务正在读取已由某个其他事务更新的值,则此事务只能在提交正在更新值的其他事务之后提交。
**可恢复调度示例**
这里 Tb 在 Ta 使用 W(X)在 X 中进行了更改之后对 X 执行读取操作,因此 Tb 只能在 Ta 的提交操作之后提交。
这里`Tb``Ta`使用`W(X)``X`中进行了更改之后对`X`执行读取操作,因此`Tb`只能在`Ta`的提交操作之后提交。
```
Ta Tb
......
......@@ -2,11 +2,11 @@
> 原文: [https://beginnersbook.com/2018/12/dbms-serializability/](https://beginnersbook.com/2018/12/dbms-serializability/)
当多个事务同时运行时,数据库可能会处于不一致状态。可串行化是一个概念,可以帮助我们检查哪些[计划](https://beginnersbook.com/2018/12/dbms-schedules/)是可串行化的。可串行化的计划是始终使数据库保持一致状态的计划
当多个事务同时运行时,数据库可能会处于不一致状态。可串行化是一个概念,可以帮助我们检查哪些[调度](https://beginnersbook.com/2018/12/dbms-schedules/)是可串行化的。可串行化的调度是始终使数据库保持一致状态的调度
## 什么是可串行化的计划
## 什么是可串行化的调度
可串行化的计划始终使数据库保持一致状态。 [串行调度](https://beginnersbook.com/2018/12/dbms-schedules/)始终是可串行化的调度,因为在串行调度中,事务仅在另一个事务完成执行时启动。但是,需要检查可串行化的非串行计划
可串行化的调度始终使数据库保持一致状态。 [串行调度](https://beginnersbook.com/2018/12/dbms-schedules/)始终是可串行化的调度,因为在串行调度中,事务仅在另一个事务完成执行时启动。但是,需要检查可串行化的非串行调度
如果 n 个事务的非串行调度等同于那些 n 个事务的串行调度,则称其为可串行化调度。串行调度不允许并发,一次只执行一个事务,另一个事件在已经运行的事务完成时启动。
......
......@@ -2,7 +2,7 @@
> 原文: [https://beginnersbook.com/2018/12/dbms-conflict-serializability/](https://beginnersbook.com/2018/12/dbms-conflict-serializability/)
[DBMS 计划](https://beginnersbook.com/2018/12/dbms-schedules/)指南中,我们了解到有两种类型的计划 - 串行和计划。非串联。串行调度不支持并发执行事务,而非串行调度支持并发。我们还在 [Serializability](https://beginnersbook.com/2018/12/dbms-serializability/) 教程中了解到,非串行调度可能会使数据库处于不一致状态,因此我们需要检查这些非串行调度以获得可串行化。
[DBMS 调度](https://beginnersbook.com/2018/12/dbms-schedules/)指南中,我们了解到有两种类型的调度 - 串行和调度。非串联。串行调度不支持并发执行事务,而非串行调度支持并发。我们还在[可串行化](https://beginnersbook.com/2018/12/dbms-serializability/) 教程中了解到,非串行调度可能会使数据库处于不一致状态,因此我们需要检查这些非串行调度以获得可串行化。
**冲突可串行化**是可串行化类型之一,可用于检查非串行调度是否可冲突串行化。
......@@ -14,32 +14,33 @@
如果它们满足以下三个条件,则说两个操作存在冲突:
这两项业务都属于不同的事务。
2.两个操作都在同一个数据项上运行。
3.至少有一个操作是写操作。
1. 这两项业务都属于不同的事务。
2. 两个操作都在同一个数据项上运行。
3. 至少有一个操作是写操作。
让我们看一些例子来理解这一点:
**例 1:**事务 T1 的操作 W(X)和事务 T2 的操作 R(X)是冲突操作,因为它们满足上述所有三个条件。它们属于不同的事务,它们正在处理相同的数据项 X,这是写操作中的一个操作。
**示例 2:**类似地,T1 的操作 W(X)和 T2 的 W(X)是冲突操作。
**例 1:**事务`T1`的操作`W(X)`和事务`T2`的操作`R(X)`是冲突操作,因为它们满足上述所有三个条件。它们属于不同的事务,它们正在处理相同的数据项 X,这是写操作中的一个操作。
**例 3:** T1 的操作 W(X)和 T2 的 W(Y)是非冲突操作,因为两个写操作都不在同一数据项上工作,因此这些操作不满足第二个条件
**示例 2:**类似地,`T1`的操作`W(X)``T2``W(X)`是冲突操作
**例 4:**类似地,T1 的 R(X)和 T2 的 R(X)是非冲突操作,因为它们都不是写操作
**例 3:**`T1`的操作`W(X)``T2``W(Y)`是非冲突操作,因为两个写操作都不在同一数据项上工作,因此这些操作不满足第二个条件
**示例 5:**类似地,T1 的 T1 和 R(X)的 W(X)是非冲突操作,因为两个操作属于同一事务 T1
**例 4:**类似地,`T1``R(X)``T2``R(X)`是非冲突操作,因为它们都不是写操作
## 冲突等价计划
**示例 5:**类似地,`T1``R(X)``T1``W(X)`是非冲突操作,因为两个操作属于同一事务`T1`
如果在交换非冲突操作之后可以将一个计划转换为其他计划,则称两个计划是冲突等效。
## 冲突等价调度
如果在交换非冲突操作之后可以将一个调度转换为其他调度,则称两个调度是冲突等效。
## 冲突可串行化检查
让我们检查一个计划是否可以冲突串行化。如果计划冲突等同于其序列计划,则称为冲突可串行化计划。让我们举几个计划的例子。
让我们检查一个调度是否可以冲突串行化。如果调度冲突等同于其序列调度,则称为冲突可串行化调度。让我们举几个调度的例子。
### 冲突可串行化的示例
让我们考虑这个计划
让我们考虑这个调度
```
T1 T2
......@@ -53,7 +54,7 @@ W(A)
```
要将此计划转换为连续计划,我们必须将事务 T2 的 R(A)操作与事务 T1 的 W(A)操作交换。但是我们不能交换这两个操作,因为它们是冲突操作,因此我们可以说这个给定的计划**而不是冲突可串行化**
要将此调度转换为连续调度,我们必须将事务`T2``R(A)`操作与事务`T1``W(A)`操作交换。但是我们不能交换这两个操作,因为它们是冲突操作,因此我们可以说这个给定的调度**而不是冲突可串行化**
让我们再看一个例子:
......@@ -71,7 +72,7 @@ W(A)
**交换非冲突操作**
在交换 T1 的 R(A)和 T2 的 R(A)后,我们得到:
在交换`T1``R(A)``T2``R(A)`后,我们得到:
```
T1 T2
......@@ -85,7 +86,7 @@ W(A)
```
在交换 T1 的 R(A)和 T2 的 R(B)后,我们得到:
在交换`T1``R(A)``T2``R(B)`后,我们得到:
```
T1 T2
......@@ -99,7 +100,7 @@ W(A)
```
在交换 T1 的 R(A)和 T2 的 W(B)后,我们得到:
在交换`T1``R(A)``T2``W(B)`后,我们得到:
```
T1 T2
......@@ -113,4 +114,4 @@ W(A)
```
在交换所有非冲突操作后,我们终于得到了一个连续的计划,因此我们可以说给定的计划是**冲突可串行化**
\ No newline at end of file
在交换所有非冲突操作后,我们终于得到了一个连续的调度,因此我们可以说给定的调度是**冲突可串行化**
\ No newline at end of file
......@@ -2,15 +2,15 @@
> 原文: [https://beginnersbook.com/2018/12/dbms-view-serializability/](https://beginnersbook.com/2018/12/dbms-view-serializability/)
在上一个教程中,我们学习了 [Conflict Serializability](https://beginnersbook.com/2018/12/dbms-conflict-serializability/) 。在本文中,我们将讨论另一种可串行化,即 **View Serializability**
在上一个教程中,我们学习了[冲突可串行化](https://beginnersbook.com/2018/12/dbms-conflict-serializability/)。在本文中,我们将讨论另一种可串行化,即 **查看可串行化**
## 什么是查看可串行化?
查看可串行化是一个查找给定[计划](https://beginnersbook.com/2018/12/dbms-schedules/)视图是否可串行化的过程。
查看可串行化是一个查找给定[调度](https://beginnersbook.com/2018/12/dbms-schedules/)视图是否可串行化的过程。
要检查给定的计划是否可视化串行化,我们需要检查给定的计划是否为 **View Equivalent** 到其序列计划。让我们举个例子来理解我的意思。
要检查给定的调度是否可视化串行化,我们需要检查给定的调度是否对其序列调度 **查看等价**。让我们举个例子来理解我的意思。
**给定计划:**
**给定调度:**
```
T1 T2
......@@ -26,8 +26,9 @@ W(Y)
```
**以上给定计划的串行计划:**
我们知道在[串行计划](https://beginnersbook.com/2018/12/dbms-schedules/)中,只有在当前运行的事务完成时才会启动事务。所以上面给出的计划的连续计划如下所示:
**以上给定调度的串行调度:**
我们知道在[串行调度](https://beginnersbook.com/2018/12/dbms-schedules/)中,只有在当前运行的事务完成时才会启动事务。所以上面给出的调度的连续调度如下所示:
```
T1 T2
......@@ -43,31 +44,31 @@ W(Y)
```
如果我们能够证明给定的计划是 **View Equivalent** 到其连续计划,那么给定的计划称为**视图 Serializable**
如果我们能够证明给定的调度对其连续调度 **查看等价**,那么给定的调度称为**视图可串行**
## 为什么我们需要查看可串行化?
我们知道,串行调度永远不会使数据库处于不一致状态,因为没有并发事务执行。但是,非串行调度可能会使数据库处于不一致状态,因为有多个事务同时运行。通过检查给定的非串行调度是否可视化串行化,我们确保它是一致的调度。
您可能想知道不是检查非串行计划是否可串行化,我们不能一直有串行计划吗?答案是否定的,因为事务的并发执行充分利用了系统资源,并且与串行调度相比要快得多。
您可能想知道不是检查非串行调度是否可串行化,我们不能一直有串行调度吗?答案是否定的,因为事务的并发执行充分利用了系统资源,并且与串行调度相比要快得多。
## 查看等效
让我们学习如何检查两个计划是否相同。
让我们学习如何检查两个调度是否相同。
如果它们满足以下所有条件,则称两个计划 T1 和 T2 是等效视图:
如果它们满足以下所有条件,则称两个调度`T1``T2`是等效视图:
1\. **初始读取:**事务中每个数据项的初始读取必须在两个计划中都匹配。例如,如果事务 T1 在调度 S1 中的事务 T2 之前读取数据项 X,则在调度 S2 中,T1 应该在 T2 之前读取 X.
1\. **初始读取:**事务中每个数据项的初始读取必须在两个调度中都匹配。例如,如果事务`T1`在调度`S1`中的事务`T2`之前读取数据项`X`,则在调度`S2`中,`T1`应该在`T2`之前读取`X`
**读取与初始读取:**您可能会对术语初始读取感到困惑。这里初始读取意味着对数据项的第一次读取操作,例如,数据项 X 可以在计划中多次读取,但是对 X 的第一次读取操作称为初始读取。一旦我们在同一篇文章的下一部分中得到示例,这将更加清晰。
**读取与初始读取:**您可能会对术语初始读取感到困惑。这里初始读取意味着对数据项的第一次读取操作,例如,数据项`X`可以在调度中多次读取,但是对`X`的第一次读取操作称为初始读取。一旦我们在同一篇文章的下一部分中得到示例,这将更加清晰。
2\. **最终写入:**每个数据项的最终写操作必须在两个计划中都匹配。例如,数据项 X 最后由事务 T1 在计划 S1 中写入,然后在 S2 中,对 X 的最后一次写操作应该由事务 T1 执行。
2\. **最终写入:**每个数据项的最终写操作必须在两个调度中都匹配。例如,数据项`X`最后由事务`T1`在调度`S1`中写入,然后在`S2`中,对`X`的最后一次写操作应该由事务`T1`执行。
3\. **更新读取:**如果在计划 S1 中,事务 T1 正在读取由 T2 更新的数据项,则在计划 S2 中,T1 应该在相同数据项上的 T2 写操作之后读取该值。例如,在调度 S1 中,T1 在 X 上执行写入操作后对 X 执行读取操作,然后在 S2 中,T1 在 T2 执行写入操作后读取 X.
3\. **更新读取:**如果在调度`S1`中,事务`T1`正在读取由`T2`更新的数据项,则在调度`S2`中,`T1`应该在相同数据项上的`T2`写操作之后读取该值。例如,在调度`S1`中,`T1``X`上执行写入操作后对`X`执行读取操作,然后在 `S2`中,`T1``T2`执行写入操作后读取`X`
## 查看可串行
如果计划视图等同于其序列计划,那么给定的计划称为 View Serializable。让我们举个例子。
如果调度视图等同于其序列调度,那么给定的调度称为查看可串行。让我们举个例子。
### 查看可串行化示例
......@@ -75,28 +76,28 @@ W(Y)
让我们检查一下可串行化的三个条件:
#### 首次读
#### 初始读取
计划 S1 中,事务 T1 首先读取数据项 X.在 S2 中,事务 T1 首先读取数据项 X.
调度`S1`中,事务`T1`首先读取数据项`X`.在`S2`中,事务`T1`首先读取数据项`X`.
让我们检查 Y.在计划 S1 中,事务 T1 首先读取数据项 Y.在 S2 中,Y 上的第一次读操作由 T1 执行。
让我们检查`Y`.在调度`S1`中,事务`T1`首先读取数据项`Y`.在`S2`中,`Y`上的第一次读操作由`T1`执行。
我们检查了数据项 X&在 S1 和 S1 中满足 Y 和**初始读取**条件。 S2
我们检查了数据项`X`和在`S1``S1`中满足`Y`**初始读取**条件
#### 最后写
#### 最终写入
在调度 S1 中,X 上的最终写操作由事务 T2 完成。在 S2 中,事务 T2 也在 X 上执行最终写入。
在调度`S1`中,`X`上的最终写操作由事务`T2`完成。在`S2`中,事务`T2`也在`X`上执行最终写入。
让我们检查 Y.在计划 S1 中,Y 上的最终写操作由事务 T2 完成。在计划 S2 中,Y 上的最终写入由 T2 完成。
让我们检查`Y`.在调度`S1`中,`Y`上的最终写操作由事务`T2`完成。在调度`S2`中,`Y`上的最终写入由`T2`完成。
我们检查了数据项 X&在 S1&中,Y 和**最终写入**条件得到满足。 S2
我们检查了数据项`X``Y`,在`S1``S2`中,**最终写入**条件得到满足
#### 更新读
#### 更新读
S1 中,事务 T2 读取由 T1 写入的 X 的值。在 S2 中,相同的事务 T2 在 T1 写入之后读取 X.
`S1`中,事务 T2 读取由 T1 写入的 X 的值。在 S2 中,相同的事务 T2 在 T1 写入之后读取 X.
S1 中,事务 T2 读取由 T1 写入的 Y 的值。在 S2 中,相同的事务 T2 在 T1 更新之后读取 Y 的值。
`S1`中,事务`T2`读取由`T1`写入的`Y`的值。在`S2`中,相同的事务`T2``T1`更新之后读取`Y`的值。
两个计划也满足更新读取条件。
两个调度也满足更新读取条件。
**结果:**由于在该示例中满足检查两个调度是否是视图等效的所有三个条件,这意味着 S1 和 S2 是视图等效的。而且,正如我们所知,计划 S2 是 S1 的连续计划,因此我们可以说计划 S1 是视图可串行化计划。
\ No newline at end of file
**结果:**由于在该示例中满足检查两个调度是否是视图等效的所有三个条件,这意味着`S1``S2`是视图等效的。而且,正如我们所知,调度`S2``S1`的连续调度,因此我们可以说调度`S1`是视图可串行化调度。
\ No newline at end of file
......@@ -3,6 +3,7 @@
> 原文: [https://beginnersbook.com/2015/04/deadlock-in-dbms/](https://beginnersbook.com/2015/04/deadlock-in-dbms/)
**死锁**是一个条件,其中两个或多个任务正在等待彼此以便完成,但任务都不愿意放弃其他任务所需的资源。在这种情况下,任务都没有完成,并且永远处于等待状态。
![Deadlock diagram](img/cdd69c2df2eb7a929543ef08db4863c2.jpg)
## 科夫曼条件
......@@ -20,7 +21,7 @@
那会让你笑吗?您可能想知道如何在死锁处理下忽略死锁。但是为了让你知道你在 PC 上使用的窗口,使用这种死锁处理方法,这是有时它会挂起的原因,你必须重新启动才能使它工作。不仅 Windows 而且 UNIX 也使用这种方法。
**问题是为什么?为什么不用处理死锁而忽略它以及为什么这被称为 Ostrich 算法呢?**
**问题是为什么?为什么不用处理死锁而忽略它以及为什么这被称为鸵鸟算法呢?**
好!让我先回答第二个问题,这就是所谓的鸵鸟算法,因为在这种方法中我们忽略了死锁并假装它永远不会发生,就像鸵鸟的行为“把头埋在沙子中假装没有问题”。
......@@ -37,7 +38,7 @@
### 死锁预防
我们已经了解到,如果所有四个 Coffman 条件都成立,则会发生死锁,因此阻止其中的一个或多个可以防止死锁。
我们已经了解到,如果所有四个科夫曼条件都成立,则会发生死锁,因此阻止其中的一个或多个可以防止死锁。
* **删除互斥**:所有资源必须是可共享的,这意味着一次可以有多个进程获取资源。这种方法几乎是不可能的。
* **删除保持和等待条件**:如果进程在开始之前获取了所需的所有资源,则可以将其删除。另一种删除此方法的方法是在进程持有时不执行请求资源的规则。
......@@ -48,13 +49,14 @@
如果以避免发生死锁的方式分配资源,则可以避免死锁。有两种算法可以避免死锁。
* 等待/
* 伤口/等待
* 等待/死亡
* 死亡/等待
以下是每种算法的资源分配的表表示。这两种算法都考虑了进程时代,同时确定了避免死锁的最佳资源分配方式。
| | 等待/模 | 伤口/等待 |
| 较旧的进程需要年轻进程持有的资源 | **旧程序**等待 | **年轻的过程**死了 |
| 较年轻的进程需要旧进程持有的资源 | **Younger process** dies | **更年轻的过程**等待 |
| | 等待/死亡 | 死亡/等待 |
| --- | --- |
| 旧进程需要新进程持有的资源 | **旧进程**等待 | **新进程**死亡 |
| 新进程需要旧进程持有的资源 | **旧进程**死亡 | **新进程**等待 |
一个着名的死锁避免算法是 **Banker 的算法**
\ No newline at end of file
一个着名的死锁避免算法是 **银行家算法**
\ No newline at end of file
......@@ -9,22 +9,23 @@
## 冲突示例
你和你的兄弟有一个联合银行账户,你可以从中提取资金。现在让我们说你们两个同时去同一家银行的不同分行尝试提取 5000 INR,你的联名账户只有 6000 余额。现在,如果我们没有并发控制,你们两个可以同时获得 5000 INR,但是一旦两个事务完成,账户余额将是-4000,这是不可能的,并使数据库处于不一致状态。
我们需要以某种方式控制事务的东西,允许事务同时运行,但保持数据的一致性以避免此类问题。
## 冲突解决方案:锁
## 冲突解决方案:锁
锁是一种确保维护数据完整性的机制。在访问数据时可以放置两种类型的锁,以便在我们处理数据时并发事务不会改变数据。
1.共享锁(S
2.专用锁(X
1. 共享锁(`S`
2. 独占锁(`X`
**1.共享锁(S)**:当我们读取数据时放置共享锁,可以在数据上放置多个共享锁,但是当放置共享锁时,不能放置独占锁。
**1\. 共享锁(`S`)**:当我们读取数据时放置共享锁,可以在数据上放置多个共享锁,但是当放置共享锁时,不能放置独占锁。
例如,当两个事务正在读取史蒂夫的账户余额时,让他们通过放置共享锁来读取,但如果另一个事务想要通过放置独家锁来更新史蒂夫的账户余额,则在读取完成之前不要允许它。
**2.独占锁定(X)**:当我们想要读取和写入数据时,放置独占锁定。此锁定允许读取和写入操作。一旦将此锁定放在数据上,就不会对数据放置其他锁定(共享或独占),直到释放独占锁定
**2\. 独占锁(`X`)**:当我们想要读取和写入数据时,放置独占锁。此锁允许读取和写入操作。一旦将此锁放在数据上,就不会对数据放置其他锁(共享或独占),直到释放独占锁
例如,当一个事务想要更新史蒂夫的账户余额时,让它通过放置 X 锁定来做,但如果第二个事务想要读取数据(S 锁定)不允许它,如果另一个事务想要写入数据(X 锁定)也不允许这样做。
例如,当一个事务想要更新史蒂夫的账户余额时,让它通过放置`X`锁来做,但如果第二个事务想要读取数据(`S`锁)不允许它,如果另一个事务想要写入数据(`X`)也不允许这样做。
所以基于此,我们可以创建一个这样的表:
......@@ -42,5 +43,7 @@ __________________________
```
**如何读取这个矩阵?:**
有两行,第一行表示当放置 S 锁时,可以获取另一个 S 锁,因此它被标记为 true 但是没有可以获得 Exclusive 锁标记为假。
在第二行中,当获取 X 锁定时,既不能获取 S 也不能获得 X 锁定,因此两者都标记为假。
\ No newline at end of file
有两行,第一行表示当放置`S`锁时,可以获取另一个`S`锁,因此它被标记为`true`但是没有可以获得独占锁标记为假。
在第二行中,当获取`X`锁时,既不能获取`S`也不能获得`X`锁,因此两者都标记为假。
\ No newline at end of file
......@@ -37,7 +37,7 @@
+ [DBMS 中的事务管理](38.md)
+ [DBMS 中的 ACID 属性](39.md)
+ [DBMS 事务状态](40.md)
+ [DBMS 计划和计划类型](41.md)
+ [DBMS 调度和调度类型](41.md)
+ [DBMS 可串行化](42.md)
+ [DBMS 冲突可串行化](43.md)
+ [DBMS 查看可串行化](44.md)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册