数据库概论
1. 定义与模型
数据库就是一个以某种有组织的方式存储的数据集合。
- 数据库持久化地存储数据,本质就是一个文件系统;
- 数据库方便存储和管理数据;
- 使用了统一的方式操作数据库——SQL。
数据库管理系统,即 DBMS,也叫数据库软件。DBMS 可分为两类:
- 基于共享文件系统的 DBMS:主要用于桌面用途,通常不用于高端或更关键的应用:如 Microsoft Access,FileMaker;
- 基于客户机-服务器的 DBMS:如 MySQL, Oracle, Microsoft SQL Server 等。
- 服务器部分是负责所有数据访问和处理的一个软件,与数据文件打交道的只有服务器软件,而客户机是与用户打交道的软件,服务器软件通过处理客户机软件进行数据增删改查等操作,并把结果返回给客户机软件;
- 所有这些活动对用户都是透明的,数据存储在别的地方,用户不需要直接访问数据文件。
数据库按照数据结构来组织、存储和管理数据,实际上,数据库一共有三种模型。
1.1 层次模型
层次模型就是以“上下级”的层次关系来组织数据的一种方式,层次模型的数据结构看起来就像一颗树。
┌─────┐
│ │
└─────┘
│
┌───────┴───────┐
│ │
┌─────┐ ┌─────┐
│ │ │ │
└─────┘ └─────┘
│ │
┌───┴───┐ ┌───┴───┐
│ │ │ │
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ │ │ │ │ │ │ │
└─────┘ └─────┘ └─────┘ └─────┘
1.2 网状模型
网状模型把每个数据节点和其他很多节点都连接起来,它的数据结构看起来就像很多城市之间的路网。
┌─────┐ ┌─────┐
┌─│ │──────│ │──┐
│ └─────┘ └─────┘ │
│ │ │ │
│ └──────┬─────┘ │
│ │ │
┌─────┐ ┌─────┐ ┌─────┐
│ │─────│ │─────│ │
└─────┘ └─────┘ └─────┘
│ │ │
│ ┌─────┴─────┐ │
│ │ │ │
│ ┌─────┐ ┌─────┐ │
└──│ │─────│ │──┘
└─────┘ └─────┘
1.3 关系模型
关系模型把数据看作是一个二维表格,任何数据都可以通过行号+列号来唯一确定,它的数据模型看起来就是一个 Excel 表。
┌─────┬─────┬─────┬─────┬─────┐
│ │ │ │ │ │
├─────┼─────┼─────┼─────┼─────┤
│ │ │ │ │ │
├─────┼─────┼─────┼─────┼─────┤
│ │ │ │ │ │
├─────┼─────┼─────┼─────┼─────┤
│ │ │ │ │ │
└─────┴─────┴─────┴─────┴─────┘
随着时间的推移和市场竞争,最终,基于关系模型的关系数据库获得了绝对市场份额。因为相比层次模型和网状模型,关系模型理解和使用起来最简单。
关系数据库的关系模型是基于数学理论建立的(参见“离散数学——集合论——二元关系”页笔记):
- 我们把域(Domain)定义为一组具有相同数据类型的值的集合,给定一组域$D_1, D_2, ..., D_n$,它们的笛卡尔集定义为$D_1 \times D_2\times ...\times D_n= { (d_1, d_2, ..., d_n)|d_i\in D_i, i=1, 2, ..., n }$
- 而$D_1 \times D_2\times ...\times D_n$的子集叫作在域$D_1, D_2, ..., D_n$上的关系,记作$R(D_1, D_2, ..., D_n)$
2. 关系数据库
2.1 市场产品
目前,主流的关系数据库主要分为以下几类:
- 商用数据库,例如:Oracle,SQL Server,DB2 等;
- 开源数据库,例如:MySQL,PostgreSQL 等;
- 桌面数据库,以微软 Access 为代表,适合桌面应用程序使用;
- 嵌入式数据库,以 Sqlite 为代表,适合手机应用和桌面程序。
2.2 相关概念
关系型数据库是建立在关系模型上的,而关系模型本质上就是若干个存储数据的二维表,可以把它们看作很多 Excel 表,但表名在同一个数据库中应该是唯一的。因而关系型数据库存在如下表、列、行的概念:
表:某种特定类型数据的结构化清单。
列:也叫做字段,其限定表中存储的信息类型,所有表都是由一个或多个列组成的。在实际工程中,正确地将数据分解为多个列极为重要。
通常情况下,列应该避免允许为 NULL。不允许为 NULL 可以简化查询条件,加快查询速度,也利于应用程序读取数据后无需判断是否为 NULL。
行:表中具象的每条数据是按行存储的,同一个表的每一行记录都拥有相同的若干字段。
在关系数据库中,关系是通过主键和外键来维护的。我们在后面会分别深入讲解。
2.3 与 Excel 表的不同
和 Excel 表有所不同的是,关系数据库的表和表之间需要建立一对多、多对一和一对一的关系,这样才能够按照应用程序的逻辑来组织和存储数据。例如,一个班级表:
ID | 名称 | 班主任 |
---|---|---|
201 | 二年级一班 | 王老师 |
202 | 二年级二班 | 李老师 |
每一行对应着一个班级,而一个班级对应着多个学生,所以班级表和学生表的关系就是“一对多”:
ID | 姓名 | 班级 ID | 性别 | 年龄 |
---|---|---|---|---|
1 | 小明 | 201 | M | 9 |
2 | 小红 | 202 | F | 8 |
3 | 小军 | 202 | M | 8 |
4 | 小白 | 201 | F | 9 |
反过来,如果我们先在学生表中定位了一行记录,例如 ID=1 的小明,要确定他的班级,只需要根据他的“班级 ID”对应的值 201 找到班级表中 ID=201 的记录,即二年级一班。所以,学生表和班级表是“多对一”的关系。
如果我们把班级表分拆得细一点,例如,单独创建一个教师表:
ID | 名称 | 年龄 |
---|---|---|
A1 | 王老师 | 26 |
A2 | 张老师 | 39 |
A3 | 李老师 | 32 |
A4 | 赵老师 | 27 |
班级表只存储教师 ID:
ID | 名称 | 班主任 ID |
---|---|---|
201 | 二年级一班 | A1 |
202 | 二年级二班 | A3 |
这样,一个班级总是对应一个教师,班级表和教师表就是“一对一”关系。
3. SQL
结构化查询语言 SQL(Structured Query Language),发音 sequel 或字母 S-Q-L,是一种专门用来与数据库通信的语言。SQL 语句既可以查询数据库中的数据,也可以添加、更新和删除数据库中的数据,还可以对数据库进行管理和维护操作。
虽然 SQL 已经被 ANSI 组织定义为标准,不幸地是,各个不同的数据库对标准的 SQL 支持不太一致。并且,大部分数据库都在标准的 SQL 上做了扩展。也就是说,如果只使用标准 SQL,理论上所有数据库都可以支持,但如果使用某个特定数据库的扩展 SQL,换一个数据库就不能执行了。例如,Oracle 把自己扩展的 SQL 称为 PL/SQL,Microsoft 把自己扩展的 SQL 称为 T-SQL。
现实情况是,如果我们只使用标准 SQL 的核心功能,那么所有数据库通常都可以执行。不常用的 SQL 功能,不同的数据库支持的程度都不一样。而各个数据库支持的各自扩展的功能,通常我们把它们称之为“方言”。
总的来说,SQL 语言可分为如下几种类型:
SQL 语句的类型 | 说明 |
---|---|
DDL(Data Definition Language) | DDL 用来操作数据库、表结构。通常,DDL 由数据库管理员执行。 |
DML(Data Manipulation Language) | DML 为用户提供添加、删除、更新数据的能力,这些是应用程序对数据库的日常操作。 |
DQL(Data Query Language) | DQL 允许用户查询数据,这也是通常最频繁的数据库日常操作。 |
简单地说,SQL 就是访问和处理关系数据库的计算机标准语言。也就是说,无论用什么编程语言(Java、Python、C++…)编写程序,只要涉及到操作关系数据库,比如,一个电商网站需要把用户和商品信息存入数据库,或者一个手机游戏需要把用户的道具、通关信息存入数据库,都必须通过 SQL 来完成。
所以,现代程序离不开关系数据库,要使用关系数据库就必须掌握 SQL。
4. NoSQL
你可能还听说过 NoSQL 数据库,也就是非 SQL 的数据库,包括 MongoDB、Cassandra、Dynamo 等等,它们都不是关系数据库。
有很多人鼓吹现代 Web 程序已经无需关系数据库了,只需要使用 NoSQL 就可以,但事实上,SQL 数据库从始至终从未被取代过。回顾一下 NoSQL 的发展历程:
- 1970: NoSQL = We have no SQL
- 1980: NoSQL = Know SQL
- 2000: NoSQL = No SQL!
- 2005: NoSQL = Not only SQL
- 2013: NoSQL = No, SQL!
今天,SQL 数据库仍然承担了各种应用程序的核心数据存储,而 NoSQL 数据库作为 SQL 数据库的补充,两者不再是二选一的问题,而是主从关系。
5. 锁的分类
悲观锁与乐观锁
- 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据时就会阻塞,直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。
- 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新数据的时候会判断一下在此期间别人有没有去更新这个数据,判断的依据是使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis 就是利用这种 check-and-set 的乐观锁机制实现事务的。
共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)
- 共享锁(S 锁):又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
- 排他锁(X 锁):又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条事务加任何类型的锁(锁不兼容)。