数据库入门¶
信息
您是一位经验丰富的开发者,并且已经了解数据库的一切了吗?🤓
那么您可以立即跳到下一节。
如果您对数据库并非了如指掌,这里有一个快速概览。
您之后总可以自行深入学习。
但这应该能帮助您开始使用数据库并高效地运用 SQLModel。🚀
什么是数据库¶
那么,什么是数据库?
数据库是一个以结构化和高效方式存储和管理数据的系统。
提示
“database”一词通常缩写为 “DB”。
由于数据库的信息量很大,而且可能非常技术化和学术化,我将在这里为您快速概览一些主要概念。
我甚至会告诉您一些不同类型的数据库,包括 SQLModel 不涵盖的数据库(“NoSQL”数据库)。
为什么要使用数据库¶
在开始编程时,可能不明显为什么拥有一个独立于程序代码的数据库是一个好主意。让我们从这里开始。
提示
如果这对于您来说显而易见,请继续阅读下面的下一节。👇
在您的代码中,您已经有了变量、字典、列表等。它们都以某种方式存储着数据。为什么您还需要一个独立的数据库呢?
如果您仔细观察,您的代码是静态的,一旦您运行它,它并不会随时间真正改变。当然,您会经常更改代码,添加功能等,但一旦您开始运行 Python 代码,程序就会保持在您启动时的状态。如果您更改了代码,程序只有在您再次运行它时才会改变。
而且即使您更改了变量中的内容,一旦程序终止,所有在内存中的数据就消失了。🔥
在大多数情况下,您的程序的目标是处理程序外部的数据。
- 它可能只是将文件从一个地方移动到另一个地方。
- 或者它可能从终端接收用户数据并以不同方式显示。
- 或者是一个接收数据并以某种方式处理的Web API等。
在大多数情况下,数据来自程序外部或在程序外部结束(例如,显示在屏幕上,在一个文件中等)。
在许多情况下,您需要您的程序能够创建和存储数据,读取数据,更新数据,删除数据等。
您可以通过从代码中读取和写入文件来完成所有这些操作。在简单的情况下,这确实有效。但对于大多数数据稍微复杂的复杂系统来说,这种策略效率不高。而且您必须处理许多注意事项,例如保持数据同步,确保数据安全存储等。
数据库旨在解决这些问题,使数据处理过程更加高效,并且独立于您的代码。✨
如何与数据库交互¶
数据库有许多类型。
单文件数据库¶
数据库可以是一个名为heroes.db的单个文件,并通过代码以非常高效的方式进行管理。一个例子是 SQLite,稍后会详细介绍。
服务器数据库¶
数据库也可以是一个作为应用程序运行在服务器上的系统,它以优化的格式在内部处理多个文件。
就像一个网络服务器,但以自定义且高效的方式进行通信。这是最常见的数据库交互类型。
在这种情况下,您的代码将与此服务器应用程序对话,而不是直接读取或修改文件。
数据库可能位于不同的服务器/机器上
或者数据库可能位于同一服务器/机器上
这类数据库最重要的一个方面是,您的代码不会直接读取或修改包含数据的文件。
相反,您的代码与数据库应用程序通信,而该数据库应用程序才是真正读取和修改其数据文件的。这是因为这个数据库应用程序通常比您的代码效率高得多。
一些以这种方式工作的数据库示例包括 PostgreSQL、MySQL 或 MongoDB。
分布式服务器¶
在某些情况下,数据库甚至可能是一组运行在不同机器上的服务器应用程序,它们协同工作并相互通信以提高效率并处理更多数据。
在这种情况下,您的代码将与这些运行在不同机器上的一个或多个服务器应用程序进行通信。
大多数作为服务器应用程序工作的数据库都以这样或那样的方式支持多个服务器。
拥有分布式系统也带来了额外的挑战,所以您很有可能首先与单个服务器应用程序或基于单个文件的应用程序进行交互。
SQL 数据库¶
我们已经讨论了与数据库交互的不同方式以及它们如何处理文件等。这适用于大多数或所有数据库。
但还有另一种非常重要的数据库分类方式。正如您可以想象的,有许多类型的数据库,每个组中也有许多数据库。但总的来说,它们可以分为两大类:“SQL 数据库”和“NoSQL 数据库”。
我们稍后会讨论为什么叫“SQL”,但首先,让我们看看它到底是什么。
用于 SQL 数据库的 SQLModel¶
SQLModel 是一个帮助您处理 SQL 数据库的工具。
它对 NoSQL 数据库帮助不大。不过,我在这里会简要介绍一下它们。
发明 SQL 数据库¶
很久以前,一些聪明人意识到存储数据的一个好方法是将其放入不同的表中。
我说的“表”指的是以网格形式排列的数据,包含不同的列和行,很像一个单一的电子表格。
每行代表一个特定的项目或记录。每列代表该记录的特定属性或字段。
一个大表的例子¶
假设我们需要存储一些关于英雄的数据。
如果我们使用一个单一的表来存储我们的英雄,它可能是这样的
| id | name | secret_name | age | 团队 | 总部 |
|---|---|---|---|---|---|
| 1 | 死侍 | 戴夫·威尔逊 | 空 | Z-Factor | 玛格丽特修女酒吧 |
| 2 | 蜘蛛男孩 | 佩德罗·帕尔克多 | 空 | 阻止者 | 锐利之塔 |
| 3 | 锈人 | 汤米·夏普 | 48 | 阻止者 | 锐利之塔 |
这可能就是我们必须用单个表(例如,单个电子表格)来做的事情。
但这有一些问题。让我们检查一下。
单表问题¶
想象一下,他们决定将“尖塔”改名为“预防者之塔”。
现在我们不得不在两个地方更新它。
如果我们的代码在一个地方开始更新这个名字,然后突然停电,电脑关机了怎么办?
我们可能会得到不一致的信息,一个地方写着“预防者之塔”,另一个地方写着“尖塔”。
| id | name | secret_name | age | 团队 | 总部 |
|---|---|---|---|---|---|
| 1 | 死侍 | 戴夫·威尔逊 | 空 | Z-部队 | 玛格丽特修女酒吧 |
| 2 | 蜘蛛男孩 | 佩德罗·帕尔克多 | 空 | 阻止者 | 预防者之塔 ✅ |
| 3 | 锈人 | 汤米·夏普 | 48 | 阻止者 | 尖塔 🚨 |
现在想象一下,我们需要添加一个新英雄,名叫“麻将”,他是“Z-Force”团队的一员。
我们可能会忘记团队的名称,最终添加“麻将”时使用了无效的团队名称,例如“Y-Force”。
| id | name | secret_name | age | 团队 | 总部 |
|---|---|---|---|---|---|
| 1 | 死侍 | 戴夫·威尔逊 | 空 | Z-部队 | 玛格丽特修女酒吧 |
| 2 | 蜘蛛男孩 | 佩德罗·帕尔克多 | 空 | 阻止者 | 预防者之塔 |
| 3 | 锈人 | 汤米·夏普 | 48 | 阻止者 | 锐利之塔 |
| 4 | 麻将 | 尼娜·瑟格尔 | 31 | Y-Force 🚨 | 玛格丽特修女酒吧 |
如果一个英雄属于两个团队呢?我们无法轻易地将这些信息放入一个大表中。
多表¶
但这些问题和其他问题可以通过将数据放入多个表中来更好地解决。
因此,我们不必用一个表包含所有数据,我们可以为英雄们创建一个表,为团队创建一个表,并找到一种方法将两者连接起来。
团队的表格可能看起来像这样
| id | name | 总部 |
|---|---|---|
| 1 | 阻止者 | 锐利之塔 |
| 2 | Z-部队 | 玛格丽特修女酒吧 |
现在,英雄的表格看起来几乎相同。但请记住,我们提到我们需要一种方法来连接这两个表格?
英雄表现在将有一个额外的列 team_id。此列显示每行(每个英雄)与其所属团队之间的关系。
| id | name | secret_name | age | 团队ID ✨ |
|---|---|---|---|---|
| 1 | 死侍 | 戴夫·威尔逊 | 空 | 2 ✨ |
| 2 | 蜘蛛男孩 | 佩德罗·帕尔克多 | 空 | 1 ✨ |
| 3 | 锈人 | 汤米·夏普 | 48 | 1 ✨ |
标识 - 主键¶
在上面的例子中,每一行都有一个 id。每个 ID 在表中都是唯一的,并标识该特定行。
这些 SQL 数据库要求有一种唯一标识表中每一行的方式。它可以是唯一的列组合,但通常只是单个列。这被称为表的“主键”。
主键通常是单个列,通常是由数据库自动生成的整数,在许多情况下,该列简单地称为id。
这个主键,在这个例子中是id列,必须在表中是唯一的。但是两个不同的表可以有相同的 ID。例如,上面两个表都有 ID 2,分别对应两个不同的行,一个用于一个表中的“Z-Force”,另一个用于另一个表中的“Spider-Boy”,但只要每个表只有一个,那仍然是可以的。
关系 - 外键¶
表中的每一行都有一个唯一的主键(在我们的例子中是一个名为id的列)。
例如,团队表的 ID 为 1 的团队是 Preventers,ID 为 2 的团队是 Z-Force。
由于这些主键 ID 可以唯一标识团队表中的每一行,我们现在可以转到英雄表并引用团队表中的这些 ID。
因此,在英雄表中,我们使用 team_id 列来定义与外部团队表的关系。英雄表中 team_id 列的每个值都将与团队表中某一行 id 列的值相同。
在英雄表中,我们有一个主键,它是id。但我们还有另一个列team_id,它指向一个外部表中的键。这也有一个技术术语,team_id 是一个“外键”。
关系与关系数据库¶
这些表格的技术和学术术语是“关系”。
在谈论这些数据库时,您可能会经常听到这个词。
它不像您在英语中那样指代事物之间的关联,即使这些表之间确实存在“关联”。
技术术语关系仅指这些表格中的每一个。
正因为这个技术术语,这些 SQL 数据库也被称为关系型数据库(事实上,这是技术上正确的术语)。但它仍然只是指这些由多个表构成的数据库。
SQL - 语言¶
在提出这些如何将数据存储到多个表中的想法之后,他们还创建了一种可用于与这些表交互的语言。
这种语言被称为 SQL,这个名字来源于 Structured Query Language(结构化查询语言)。
然而,这种语言不仅用于查询数据。它还用于创建记录/行、更新它们、删除它们。以及操作数据库、创建表等。
所有处理多个表的数据库都支持这种语言,这就是它们被称为 SQL 数据库的原因。尽管每个数据库支持的 SQL 语言都有细微的变化(方言)。
假设存储英雄的表叫做 hero 表。一个获取其中所有数据的 SQL 查询示例可能如下所示
SELECT *
FROM hero;
该 SQL 查询将返回表
| id | name | secret_name | age | 团队ID |
|---|---|---|---|---|
| 1 | 死侍 | 戴夫·威尔逊 | 空 | 2 |
| 2 | 蜘蛛男孩 | 佩德罗·帕尔克多 | 空 | 1 |
| 3 | 锈人 | 汤米·夏普 | 48 | 1 |
用于 SQL 的 SQLModel¶
SQLModel 是一个库,它帮助您使用常规 Python 对象编写 Python 代码,然后将其转换为发送到 SQL 数据库的 SQL 语句。
接下来,它接收数据并将其放入 Python 对象中,您可以继续在代码中使用这些对象。
在接下来的章节中,我将详细介绍 SQL、SQLModel、它们的使用方法以及它们之间的关系。
技术细节
SQLModel 是基于 SQLAlchemy 构建的。事实上,它就是 SQLAlchemy 和 Pydantic 加上一些额外的功能混合在一起。
NoSQL 数据库¶
尽管 SQL 数据库是历史最悠久、使用最广泛的数据库类型,但还有另一类(非常有趣)的数据库,即 NoSQL 数据库。
NoSQL 数据库涵盖了广泛的不同子类型,包括键值存储、文档存储、图数据库等等。
SQLModel 只能帮助您处理 SQL 数据库。因此,接下来的文档中我们将讨论这方面的内容。