问题

大学生如何实现一个数据库?

回答
大学生如何实现一个数据库?

大学生实现一个数据库,这不仅仅是掌握一项技术,更是一个深入理解数据存储、管理和交互的绝佳机会。这个过程可以从简单到复杂,逐步深入。下面我将从概念、工具选择、具体实现步骤以及进阶学习等方面,详细阐述大学生如何实现一个数据库。

一、 理解数据库的核心概念

在动手之前,理解数据库的基本原理至关重要。

1. 什么是数据库?
数据库(Database,DB)是按照一定结构组织、存放数据的仓库。
它可以被看作是一个电子表格的集合,但功能远不止于此。
主要目的是高效地存储、检索、管理和更新数据。

2. 数据库管理系统(DBMS)
DBMS 是一个软件系统,用于创建、维护和使用数据库。
它充当用户和数据库之间的接口,负责数据的安全性、完整性、并发控制等。
常见的 DBMS 有:MySQL, PostgreSQL, SQL Server, Oracle, SQLite 等。

3. 数据模型
数据模型描述了数据如何组织和表示。
关系型模型 (Relational Model) 是目前最主流的模型,数据存储在表中,表之间通过关系(键)连接。
表 (Table):由行(记录)和列(字段/属性)组成。
行 (Row/Record):代表一个独立的数据项。
列 (Column/Field/Attribute):代表数据的某个属性。
主键 (Primary Key):唯一标识表中每一行的字段或字段组合。
外键 (Foreign Key):指向另一个表中主键的字段,用于建立表之间的关系。

4. SQL (Structured Query Language)
SQL 是用于管理关系型数据库的标准语言。
它用于查询、插入、更新和删除数据,以及创建和修改数据库结构。
DML (Data Manipulation Language):用于操作数据,如 `SELECT`, `INSERT`, `UPDATE`, `DELETE`。
DDL (Data Definition Language):用于定义数据库结构,如 `CREATE TABLE`, `ALTER TABLE`, `DROP TABLE`。

二、 选择合适的工具和技术栈

对于大学生而言,选择易于上手且功能强大的工具是关键。

1. 数据库类型选择:
关系型数据库 (RDBMS):
MySQL: 开源免费,社区庞大,功能强大,是学习和实践的首选。非常适合初学者。
PostgreSQL: 开源免费,功能比 MySQL 更强大,更符合 SQL 标准,适合更复杂的应用。
SQLite: 一个轻量级的嵌入式数据库,不需要单独安装服务器,数据直接存储在文件中。非常适合个人项目、移动应用或简单桌面应用。
非关系型数据库 (NoSQL):
MongoDB (文档数据库): 适合存储结构不固定的数据,如 JSON 文档。
Redis (键值数据库/缓存): 非常适合用作缓存、会话存储等。
Neo4j (图数据库): 适合存储和查询关系复杂的网络数据。

建议: 对于大学生初次实现数据库,强烈推荐从 MySQL 或 SQLite 开始学习。MySQL 提供了完整的客户端/服务器架构体验,SQLite 则更简单,可以直接嵌入到项目中。

2. 客户端工具选择:
MySQL:
MySQL Workbench: 官方提供的免费图形化管理工具,功能全面,包括数据库设计、SQL开发、服务器管理等。
DBeaver: 一个免费开源的通用数据库工具,支持多种数据库,功能强大且界面友好。
Navicat (付费,但有试用期或教育版): 非常流行的数据库管理工具,功能强大,用户体验好。
SQLite:
DB Browser for SQLite: 免费开源的 SQLite 数据库图形化管理工具,非常直观易用。

3. 编程语言集成:
你将需要一种编程语言来与数据库交互,执行 SQL 查询并将结果集成到你的应用程序中。
Python: 拥有强大的数据库连接库(如 `mysqlconnectorpython` for MySQL, `sqlite3` module for SQLite)和 ORM (ObjectRelational Mapping) 框架 (如 SQLAlchemy),非常适合快速开发。
Java: 使用 JDBC (Java Database Connectivity) API,并有 Hibernate, MyBatis 等 ORM 框架。
Node.js (JavaScript): 使用 `mysql` 或 `pg` (for PostgreSQL) 等库,以及 Sequelize, TypeORM 等 ORM。

建议: 如果你已经熟悉 Python,那么它将是与数据库交互的最佳选择。

三、 实现数据库的具体步骤(以 MySQL 为例)

这里以在本地搭建一个 MySQL 数据库并通过 Python 与之交互为例,来详细说明实现步骤。

步骤一:安装 MySQL 服务器

1. 下载 MySQL:
访问 MySQL 官网(dev.mysql.com/downloads/mysql/)。
选择适合你操作系统的 MySQL Community Server 版本。通常下载 MySQL Installer (Windows) 或通过包管理器安装 (macOS/Linux)。
2. 安装过程:
Windows: 运行 MySQL Installer,选择“Custom”安装类型,确保勾选 `MySQL Server` 和 `MySQL Workbench`。在安装过程中会让你设置 `root` 用户密码,请务必记牢。
macOS: 可以通过 Homebrew (`brew install mysql`) 或下载 DMG 文件安装。安装后需要启动 MySQL 服务。
Linux: 通常使用包管理器安装,例如 Ubuntu/Debian 使用 `sudo apt update && sudo apt install mysqlserver`。安装后需要启动服务并进行安全配置 (`sudo mysql_secure_installation`)。
3. 验证安装:
打开终端或命令提示符。
输入 `mysql u root p`,然后输入你设置的 `root` 密码。如果成功登录到 MySQL 命令行提示符 (`mysql>`),说明安装成功。

步骤二:使用 MySQL Workbench 设计和创建数据库结构

1. 连接到 MySQL 服务器:
打开 MySQL Workbench。
点击左上角的 `+` 号,创建一个新的数据库连接。
输入连接名称(例如,“MyProjectDB”)。
Hostname: `localhost` (如果 MySQL 在同一台机器上)
Port: `3306` (MySQL 默认端口)
Username: `root`
Password: 你设置的 `root` 密码。
点击 `Test Connection` 确认连接成功,然后点击 `OK` 保存。
双击新建的连接,即可进入数据库管理界面。

2. 创建数据库 (Schema):
在 MySQL Workbench 的左侧导航栏中,右键点击空白区域,选择 `Create Schema...`。
输入数据库名称(例如,“student_management”)。
点击 `Apply`。Workbench 会生成 `CREATE SCHEMA student_management` SQL 语句,再次点击 `Apply` 执行。
现在,你在左侧导航栏的“Schemas”列表中可以看到你的新数据库。选中你的数据库,这样后面的操作都会在这个数据库中进行。

3. 创建表 (Tables):
在左侧导航栏中,展开你的数据库,右键点击 `Tables`,选择 `Create Table...`。
设计一个例子: 假设我们要做一个简单的学生信息管理系统,需要 `students` 表和 `courses` 表,以及一个关联表 `student_courses` 来记录学生选修了哪些课程。

`students` 表:
列名 (Column Name) | 数据类型 (Data Type) | 主键 (PK) | 非空 (NN) | 唯一 (UQ) | 默认值 (Default) | 索引 (Index) | 自动递增 (AI)
`student_id` | `INT` | `YES` | `YES` | `YES` | `NULL` | `PRIMARY KEY` | `YES`
`name` | `VARCHAR(100)` | `NO` | `YES` | `NO` | `NULL` | `NO` | `NO`
`major` | `VARCHAR(50)` | `NO` | `NO` | `NO` | `NULL` | `NO` | `NO`
`enrollment_date` | `DATE` | `NO` | `NO` | `NO` | `NULL` | `NO` | `NO`

在 Workbench 的“Create Table”界面,逐个添加这些列。点击 `student_id` 列右侧的 `PK` 图标,将其设为主键;点击 `NN` 图标,将其设为非空;点击 `AI` 图标,将其设为自动递增。

`courses` 表:
列名 (Column Name) | 数据类型 (Data Type) | 主键 (PK) | 非空 (NN) | 唯一 (UQ) | 默认值 (Default) | 索引 (Index) | 自动递增 (AI)
`course_id` | `INT` | `YES` | `YES` | `YES` | `NULL` | `PRIMARY KEY` | `YES`
`course_name` | `VARCHAR(100)` | `NO` | `YES` | `NO` | `NULL` | `NO` | `NO`
`credits` | `INT` | `NO` | `NO` | `NO` | `NULL` | `NO` | `NO`

`student_courses` 表 (关联表):
列名 (Column Name) | 数据类型 (Data Type) | 主键 (PK) | 非空 (NN) | 唯一 (UQ) | 默认值 (Default) | 索引 (Index) | 自动递增 (AI)
`student_id` | `INT` | `YES` | `YES` | `NO` | `NULL` | `FK` | `NO`
`course_id` | `INT` | `YES` | `YES` | `NO` | `NULL` | `FK` | `NO`
`enrollment_date` | `DATE` | `NO` | `NO` | `NO` | `CURRENT_DATE` | `NO` | `NO`

设置联合主键和外键:
在 `student_courses` 表设计界面,选中 `student_id` 和 `course_id` 两列,点击工具栏中的 `PK` 图标,将它们设为联合主键。
在 `student_id` 列的“Foregin Key”一栏,选择 `FK_students` (如果之前创建 `students` 表时自动生成了,或者你需要手动创建一个)。点击右侧的按钮,弹出“Edit Foreign Key”窗口。在“Referenced Table”中选择 `students`,在“Referenced Column”中选择 `student_id`。
同理,为 `course_id` 列设置指向 `courses` 表 `course_id` 的外键。
点击 `Apply` 完成表创建。

4. SQL 语句创建表(可选,更灵活):
在 MySQL Workbench 的 SQL 标签页中,你可以直接编写 SQL 语句来创建数据库和表。
示例 SQL:
```sql
创建数据库 (如果不存在)
CREATE DATABASE IF NOT EXISTS student_management;

使用数据库
USE student_management;

创建 students 表
CREATE TABLE students (
student_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
major VARCHAR(50),
enrollment_date DATE
);

创建 courses 表
CREATE TABLE courses (
course_id INT AUTO_INCREMENT PRIMARY KEY,
course_name VARCHAR(100) NOT NULL,
credits INT
);

创建 student_courses 关联表
CREATE TABLE student_courses (
student_id INT,
course_id INT,
enrollment_date DATE DEFAULT CURRENT_DATE,
PRIMARY KEY (student_id, course_id), 联合主键
FOREIGN KEY (student_id) REFERENCES students(student_id) ON DELETE CASCADE, 外键关联 students 表,学生删除时,关联记录也删除
FOREIGN KEY (course_id) REFERENCES courses(course_id) ON DELETE CASCADE 外键关联 courses 表,课程删除时,关联记录也删除
);
```
编写完 SQL 后,点击工具栏上的闪电图标执行。

步骤三:在数据库中插入数据

1. 使用 Workbench 插入数据:
在左侧导航栏中,右键点击表名(如 `students`),选择 `Select Rows`。会生成 `SELECT FROM students` SQL 语句。执行后会显示一个数据编辑网格。
双击网格中的空白单元格可以编辑或输入新数据。输入完一行后按回车,会自动进入下一行。
点击工具栏的“Apply”按钮会生成 `INSERT` SQL 语句并执行。
2. 使用 SQL 插入数据:
```sql
插入学生数据
INSERT INTO students (name, major, enrollment_date) VALUES
('张三', '计算机科学', '20220901'),
('李四', '软件工程', '20220901'),
('王五', '网络空间安全', '20230901');

插入课程数据
INSERT INTO courses (course_name, credits) VALUES
('数据结构', 3),
('算法导论', 4),
('操作系统', 3);

关联学生和课程
INSERT INTO student_courses (student_id, course_id) VALUES
(1, 1), 张三 选修 数据结构
(1, 2), 张三 选修 算法导论
(2, 1), 李四 选修 数据结构
(2, 3), 李四 选修 操作系统
(3, 1), 王五 选修 数据结构
(3, 2), 王五 选修 算法导论
(3, 3); 王五 选修 操作系统
```

步骤四:使用 Python 与数据库交互

1. 安装 MySQL Connector/Python:
```bash
pip install mysqlconnectorpython
```
(如果你使用的是其他数据库如 PostgreSQL,则安装 `psycopg2` 等对应库)

2. 编写 Python 代码:
```python
import mysql.connector
from mysql.connector import Error

数据库连接配置
db_config = {
"host": "localhost",
"user": "root",
"password": "YOUR_ROOT_PASSWORD", 替换成你的 root 密码
"database": "student_management"
}

def create_connection():
"""创建数据库连接"""
connection = None
try:
connection = mysql.connector.connect(db_config)
if connection.is_connected():
print("成功连接到 MySQL 数据库")
except Error as e:
print(f"连接数据库时出错: {e}")
return connection

def execute_query(connection, query, params=None):
"""执行 SQL 查询,支持参数化查询以防 SQL 注入"""
cursor = connection.cursor()
try:
cursor.execute(query, params)
connection.commit() 提交事务 (对于 INSERT, UPDATE, DELETE)
print("查询执行成功")
return cursor 返回 cursor 以便获取插入 ID 等信息
except Error as e:
print(f"执行查询时出错: {e}")
connection.rollback() 发生错误时回滚
return None
finally:
if cursor:
cursor.close()

def fetch_data(connection, query, params=None):
"""执行查询并返回结果"""
cursor = connection.cursor(dictionary=True) dictionary=True 使结果为字典列表
try:
cursor.execute(query, params)
results = cursor.fetchall()
return results
except Error as e:
print(f"获取数据时出错: {e}")
return None
finally:
if cursor:
cursor.close()

def main():
connection = create_connection()

if connection:
示例:插入新学生并获取其 ID
new_student_query = "INSERT INTO students (name, major, enrollment_date) VALUES (%s, %s, %s)"
student_data = ('赵六', '人工智能', '20230901')
cursor = execute_query(connection, new_student_query, student_data)
if cursor:
new_student_id = cursor.lastrowid
print(f"新插入的学生 ID: {new_student_id}")

示例:查询所有学生及其选修的课程
query_student_courses = """
SELECT
s.name AS student_name,
c.course_name,
sc.enrollment_date
FROM
students s
JOIN
student_courses sc ON s.student_id = sc.student_id
JOIN
courses c ON sc.course_id = c.course_id
WHERE
s.student_id = %s
"""
student_id_to_query = 1 查询张三的课程
student_courses = fetch_data(connection, query_student_courses, (student_id_to_query,))

if student_courses:
print(f" 学生 (ID: {student_id_to_query}) 选修的课程:")
for row in student_courses:
print(f" 课程: {row['course_name']}, 选课日期: {row['enrollment_date']}")
else:
print(f"未找到 ID 为 {student_id_to_query} 的学生或其选修课程。")

示例:查询某门课程的学生
query_course_students = """
SELECT
s.name AS student_name,
s.major
FROM
students s
JOIN
student_courses sc ON s.student_id = sc.student_id
JOIN
courses c ON sc.course_id = c.course_id
WHERE
c.course_name = %s
"""
course_name_to_query = '数据结构'
course_students = fetch_data(connection, query_course_students, (course_name_to_query,))

if course_students:
print(f" 选修课程 '{course_name_to_query}' 的学生:")
for row in course_students:
print(f" 姓名: {row['student_name']}, 专业: {row['major']}")
else:
print(f"未找到选修课程 '{course_name_to_query}' 的学生。")


connection.close()
print("数据库连接已关闭")

if __name__ == "__main__":
main()
```
注意:
将 `YOUR_ROOT_PASSWORD` 替换为你自己的 MySQL root 密码。
`params=()` 中的 `()` 是为了确保传递的是一个元组,即使只有一个参数也要这样写。
`dictionary=True` 参数在 `connection.cursor()` 中非常有用,它使得 `fetchall()` 返回的结果是字典列表,而不是元组列表,更易于阅读和使用。

四、进阶学习与实践建议

1. SQL 进阶:
JOIN 语句: 熟练掌握 `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `FULL OUTER JOIN`。
子查询 (Subqueries): 在 WHERE, SELECT, FROM 子句中使用子查询。
聚合函数 (Aggregate Functions): `COUNT`, `SUM`, `AVG`, `MAX`, `MIN` 结合 `GROUP BY` 和 `HAVING`。
窗口函数 (Window Functions): 例如 `ROW_NUMBER()`, `RANK()`, `LAG()`, `LEAD()` 等,用于更复杂的分析。
索引 (Indexes): 理解索引的作用,如何创建和优化,以提高查询性能。
视图 (Views): 创建虚拟表,简化复杂查询。
存储过程 (Stored Procedures) 和触发器 (Triggers): 在数据库服务器端执行代码,实现更复杂的业务逻辑和自动化。

2. 数据库设计原则:
范式 (Normalization): 了解 1NF, 2NF, 3NF 等,学习如何设计出减少数据冗余、避免更新异常的数据库结构。
ER 图 (EntityRelationship Diagram): 学习使用 ER 图来可视化和设计数据库结构。

3. ORM 框架:
一旦熟悉了原始 SQL,可以尝试学习 ORM 框架,如 Python 的 SQLAlchemy。ORM 可以将数据库表映射到 Python 类,让你用面向对象的方式操作数据库,减少编写 SQL 的工作量,并提供数据库抽象。

4. 其他数据库系统:
尝试使用 PostgreSQL 来体验其更强大的功能和更严格的标准。
学习 NoSQL 数据库,了解它们的应用场景和优势,例如用 MongoDB 构建一个简单的博客系统。

5. 项目实践:
将数据库应用到你的课程项目、个人网站、毕业设计或任何你感兴趣的项目中。例如:
学生成绩管理系统
图书借阅管理系统
简单的电商商品管理
个人博客后台
社交网络用户数据管理

五、总结

大学生实现一个数据库,最实际的路径是:

1. 理解核心概念: 数据库、DBMS、SQL、表、字段、主键、外键。
2. 选择合适工具: 推荐 MySQL + MySQL Workbench + Python。
3. 动手实践:
安装 MySQL 服务器。
使用 Workbench 设计和创建数据库及表。
插入和查询数据。
学习使用 Python 连接数据库,执行增删改查操作。
4. 深入学习: 掌握更高级的 SQL、数据库设计原则,并尝试其他数据库系统和 ORM 框架。

这个过程会让你对数据有更深刻的理解,并掌握一项非常重要的 IT 技能,为未来的学习和工作打下坚实的基础。祝你实践顺利!

网友意见

user avatar

工作两年回看,当时自豪的作品已变成了玩具;

不变的是对技术的好奇和热情;

18年底加入PingCAP,真正迈入了DB领域;

有兴趣的同学可看看TiDB系列文章,并贡献PR成为contributor,满足自己好奇心并为开源社区创造价值;

对PingCAP有兴趣的同学也可内推实习或者工作;


=====================

更新了一篇boltDB的模型和分析文档, 感兴趣的同学可以看看 github.com/qw4990/blog/

=====================

大概半年前, 我收到了这个问题的邀请.

现在我数据库完成, 我觉得我有底气回答这个问题了.

算是对我这将近一年工作的总结, 也当做是一些分享(zhuangX).



我大致说一下我从一开始做, 到完成我的作品, 大致经历了哪些阶段, 以做参考.

这里是我作品的github: GitHub - qw4990/NYADB2: NYADB2



PS:

因为大家对数据库的认知和了解都不同, 所以我的切入点必定无法满足所有人.

不过我想会关注这个问题的人, 大多应该都是用过简单的数据库功能, 感觉非常好奇, 想自己实现一个的人, 就同一年前的我一样.



下面我描述了我实现DB的各个阶段, 你可以在任意一个阶段停下, 然后实现它.



========================================================================================================================================



阶段1: 无事务, 单线程, 仅存在于内存的数据库.

该状态下的数据库, 其实就是一个”索引结构”+”语法分析器”.

语法分析器分析SQL语句, 然后根据逻辑, 去执行相应的操作.

索引结构则是用来快速查询.

由于该版本仅存在于内存, 所以只要你会一些常见的索引算法, 即可完成, 可以称之为”简易内存数据库”.

如你会B+树算法, 就可以实现一个B+树, Bt.

它实现了两个接口, Bt.Insert(key, value) -> void, Bt.Search(key) -> value.

再实现一个”语法分析器”.

如来了一条语句”Insert into student value (tony, 22, 123)”.

”语法分析器”分析该语句, 将value包裹一下, 选取一个该value的键值key.

然后调用 Bt.Insert(key, value).

之后执行”Read from student …” 其实也就是分析一下, 然后执行Bt.Search(key).

该版本数据库完成.



========================================================================================================================================



阶段2: 无事务, 单线程, 不可靠的磁盘数据库

“磁盘”表示该版本将信息存放在磁盘上.

“不可靠”表示, 当数据库被非正常结束时, 不保证重启后, 数据库内容还会正确.



2.1: 思路描述

该版本也非常简单, 直接在版本1上修改.

可以这样, 如你索引结构的最小单位为Unit, (如B+树的每个节点就是一个Unit).

你将Unit编码成二进制数据, 然后为每个Unit, 在某个文件中, 分配一段固定的空间, 用来存放它.

于是, 当你需要Unit的信息是, 你从该文件的固定位置读入.

当修改Unit的信息后, 你再将它写到那个固定位置.

如此一来, 数据就被存放于磁盘上了.



2.2: 实现

这里为B+树提供一种最简单的思路.

首先将索引数据和实际数据分别存放于两份文件, 称之为IndexFile, DB.

B+树有一个BALANCE_NUMBER, 简称BN, 为定值, 那么一个B+树节点最多有2*BN个(key, value)的键值对.

我们将key固定为uint64, value固定为uint64类型.

那么一个B+树节点最多占用(8+8)*2*BN这么多byte, 将其表示为MAX_BYTES.

于是, 就可以这样来编码B+树了.

规定根节点在IndexFile的位移为0.

每当创建新的节点时, 在IndexFile尾部, 追加MAX_BYTES大小的空间.

然后将该空间在IndexFile的位移, 作为这个新节点的”位置”, 用该空间存放新节点.

于是, B+树内部节点的value就用来存放”对应子节点的位置”.

叶节点的value, 也被作为”位置”, 指向了该条记录在DB中的位移.



2.3: 优化

上述实现会频繁的读写磁盘文件, 效率影响甚大.

为了解决这个问题, 可以加入一个模块, 这个模块分页管理IndexFile文件, 并对其进行必要的缓存, 以加快访问效率.

关于分页管理细节, 缓存算法, 不展开说了.




========================================================================================================================================



阶段3: 单事务, 单线程, 可靠的磁盘数据库

版本3在2的基础上, 同时支持了事务和数据库可靠性.



3.1: 关于事务

首先需要了解事务的基本概念, 参考<<数据库系统概念>>.

事务有ACID的性质, 由于现在是单线程版本, 所以不考虑其隔离性(I).

对于ACD这几个性质, 通常配合一定的”日志机制”完成.

于是需要去了解常见的”日志机制”.

这里推荐<<数据库系统概念>>日志恢复的那几章节.



3.2: 实现

有了”日志机制”, 具体实现的时候还要考虑一些更加细节的东西.

这里是Sqlite的一篇官文, 描述了一些错误会怎么发生, 应该对操作系统做什么样的假设.

不必了解该文档每个细节, 但是可以扩展下思路: How To Corrupt An SQLite Database File

这里是Sqlite官方介绍怎么实现原子性的文档: Atomic Commit In SQLite

同样不需要了解每个细节, 可以扩展下思路.



3.3: 个人总结

通常, 利用设计好的日志机制来保证事务的ACD性质.

然后利用对操作系统的一些假设, 来保证关键信息的原子性修改, 如数据库的”Boot”信息等.

如在我自己的实现中, 我就假设了操作系统的”rename”是原子性的.




========================================================================================================================================



阶段4: 多事务, 多线程, 可靠的数据库

前面三个阶段已经有一些内容了, 但是和多线程下的情况相比, 微不足道.




4.1: 可串行化调度

首先需要了解操作冲突的概念, 可串行化调度, 以及解决该问题的”两段锁协议”等, 推荐<<数据库系统概念>>.

两段锁协议会带来一个新的问题, 死锁.

于是, 你还需要去了解解决死锁的一些办法.

我使用的是有向图判环. <<数据库系统概念>>中有一定的介绍.




4.2: 解决读写冲突

使用”两段锁”能够完成可串行化调度, 但是它会造成”读写阻塞”, 很影响数据库的效率.

当然, 你也可以不解决该问题.

不过我借鉴了Postgresql, 引用了MVCC(多版本并发控制)来解决该问题.

MVCC的资料就大家自行搜索.

总体思路大致是: 为每条数据维护多个版本, 如果事务1锁定了该条数据, 而事务2准备读取的话, 就返回给事务2更老的版本.




4.3: 事务隔离度

还是得先了解隔离度的基本概念: 事务隔离

然后在MVCC的基础上, Postgresql通过维护各个版本对事务的可见性, 来实现了多种隔离度.

关于Postgresql怎么实现MVCC, 也请大家自行搜索, 或者直接看我的模型中的VM模块, 我借鉴了此方法.




4.4: 并发的索引

除了事务本身需要进行并发控制, 之前那些没考虑并发的模块, 也要加上并发支持.

其中最重要的一个就是并发的索引结构.

B+树本身是不支持并发访问的, 为了让他支持并发, 需要设计一些协议, 或者更改B+树算法来保证其支持并发.

我借鉴了一份文档的办法, 引入了这份B+树并发访问协议: Sixth Chapter

解决了该问题.




4.5: 总结

4.1到4.4大致说明了并发的情况下, 数据库会遇到哪些新的问题, 以及解决它们的办法.

虽然每个小节都只有几句话, 但是坑挺深, 每个问题都有各种各样的解决办法, 我只说了我使用到的.

但是, 比起单个解决这些问题, 最重要的, 是考虑怎么让它们组合起来使用也不会出错.

在组合这些方法的过程中, 你需要对这些方法做调整, 其实也就是设计并组合你自己的模块, 这非常重要, 也非常有趣.

如果想明白了上面各种方法怎么协同工作, 且发现不会引入新的问题, 那么可以把上面所有方法的总结抽象为一个完整”模型”了.

而下一步就是将这个”模型”实现.




========================================================================================================================================



阶段5: 实现版本4

想清楚了模型, 那么开始实现它.



5.1: 准备

首先需要肯定的是将会在编程中用到并发, 需要去了解一些常见的并发概念, 问题, 以及解决方法.

如临界区, 信号量, 锁, 读者写者问题, 哲学家就餐问题等概念.

接着你需要选择一门并发支持较好的语言(我选的是Go).

然后去学习该语言的一些并发编程技巧.




5.2: 开始编程

这个过程就没什么可以多说的了, 就是考验编程功底.

将模型抽象清楚, 然后开始写:)

我前后的尝试过程大致为:

  1. 一开始尝试用c++写个单线程版本, 后面放弃了.
  2. 用java实现了一个单线程版本, 总共大概约1200行.
  3. 尝试用java实现多线程版本, 最后放弃了.
  4. 用Go实现了一个多线程版本, 最后代码加注释大致10000行.
  5. 重构了Go的多线程版本, 得到现在的版本, 注释加代码大概7500行.

整个过程是痛苦并快乐的, 毫无疑问非常锻炼编程和抽象能力.


========================================================================================================================================

阶段6: 测试



6.1: 各模块测试

这里的测试包括分模块测试和整体测试.

你设计的各个模块之间, 应该是可以通过指定一些"协议"来解耦的.

于是模拟这些协议, 你的模块应该是可以单独被独立测试的.

如模块A对模块B的访问遵循了协议C.

现在你想单独测试模块B, 那么可以编写一个MockA, 模拟A的操作, 并且遵守协议C.

这样讲B和MockA一起测试.



6.2: 整体测试

其实我自己的DB在整体测试上做的是不够的.

目前我针对一些特定功能, 做了一些手动的测试.

关于更好的测试方法目前我也还在思考中.




========================================================================================================================================

其他问题:

实实在在的实现一个数据库当然还有其他很多问题, 如Server与Client的交互方法, 制定自己的SQL文法, 怎么有效优雅的解析SQL语句, 数据库运行状态的监控, 对日志文件进行自动归档等.

我上面描述的是”数据库引擎”需要解决的重点问题, 这些问题就略过了.

这些问题都是可以被作为"甜点", 在"主菜"完成后慢慢品尝的.

所以分清楚哪些问题是重点, 哪些问题是可以之后慢慢解决的也很重要.

总的来说, 只要你设计好了自己的"模型", "模型"之外的问题, 几乎都可以被作为"甜点"了.




========================================================================================================================================

总结:

数据库的功能点非常多, 选好要解决的问题, 然后去查找对应问题的解决办法.

接着将这些单个问题的解决办法, 组合成一个能正确工作的模型.

每个数据库都有自己的模型, 设计这个模型是数据库最好玩, 也是最难的地方, 这是"主菜".

将模型抽象好, 用合适的方法去将其实现, 这是难点二.

这个难点就没有多说的了, 就考验编程功底.

最后就是对数据库进行测试, 以及不断的完善.

则是"甜点"了.

所以数据库不管在理论, 还是工程上, 还是在考验人的耐心上, 真是都挺难啊哈哈= =.




========================================================================================================================================



一些可能会用到的资料推荐:

1.可以看一下简单的自动机实现, 用于分析语法.

2.B+树算法, 常见的缓存算法等, 推荐看wiki.

3.<<数据库系统概念>>, 这本书可以看看有关事务, 恢复, 锁的那几章, 以做基础概念.

4.<<inside sqlite>>, 这本书介绍了sqlite的后端模型, 原书非常短小, 大概80到100页.

5.http://www.sqlite.org/howtocorrupt.html, www3.sqlite.org/atomicc 这两篇Sqlite官方文档, 当做开阔思路.

6.<<SQLite Database System: Design and Implementation>>, 也是介绍Sqlite实现的书, 和<<inside sqlite>>有部分重复, 可以选看.

7.MVCC的相关文档以及Postgresql的可见性逻辑, 请自行谷歌.

8.然后, 就是我自己实现的数据库模型文档了: gitbook.com/book/qw4990

9.最后, 最重要的还是自己思考. 遇到一个问题, 解决一个问题.




========================================================================================================================================



本人很少上知乎, 虽然在知乎发了这篇文, 但还是鼓励大家多动手, 少上知乎. (会被和谐么?

最后, 感谢一直给予我帮助的左老师:)

类似的话题

  • 回答
    大学生如何实现一个数据库?大学生实现一个数据库,这不仅仅是掌握一项技术,更是一个深入理解数据存储、管理和交互的绝佳机会。这个过程可以从简单到复杂,逐步深入。下面我将从概念、工具选择、具体实现步骤以及进阶学习等方面,详细阐述大学生如何实现一个数据库。 一、 理解数据库的核心概念在动手之前,理解数据库的.............
  • 回答
    复旦金融大一新生,梦想着年薪百万,这可不是一个空穴来风的目标,而是可以通过清晰的规划和不懈的努力来实现的。作为一名初入金融殿堂的学生,你的起点非常棒,接下来的每一步都需要走得扎实而有策略。首先,夯实基础是你的第一要务。 学业为王: 别觉得大一就谈年薪百万太早,其实现在就开始打好根基至关重要。你的.............
  • 回答
    两位法师的遭遇战,这就像是棋盘上的两颗顶尖棋子,一旦落下,便立刻展开了一场精妙绝伦的较量。没有体术的限制,他们完全依赖于手中的法器和自身对魔法的理解。实力相差不大,意味着这场战斗不会是一面倒的碾压,而是充满了策略、预判和心理博弈。开局的瞬间:感知与试探战斗的开端往往是最为紧张和充满不确定性的。在遭遇.............
  • 回答
    大学里的生产实习,特别是那种一刀切、强制性的、让学生去工厂流水线上做一个月“搬运工”的安排,这事儿吧,怎么说呢,就像是往一道精雕细琢的菜里突然扔了一把粗盐,味道是什么样,全看那把盐有多粗,还有厨师怎么调和了。先来说说这种实习的初衷。理论上,学校安排这种实习,无非是想让咱们这些坐在象牙塔里的学子们,能.............
  • 回答
    恒大召开了声势浩大的动员大会,许家印在会上掷地有声地宣誓,“恒驰5”必须在6月22日实现量产。这无疑是当前舆论焦点,也牵动着无数关注中国汽车产业发展的人们的心。那么,恒大汽车,尤其是寄予厚望的“恒驰5”,其前景究竟如何?这需要我们从多个维度进行细致的审视。一、 宏伟蓝图下的现实挑战:量产的“最后一公.............
  • 回答
    NASA 耗资 3.3 亿美元,计划用宇宙飞船撞击小行星,这绝非儿戏,而是基于科学探索和潜在生存需求的深远考量。这项名为“双小行星重定向测试”(DART)的任务,其核心目标是测试一种全新的行星防御策略——动能撞击法,以应对未来可能威胁地球的小行星撞击风险。计划的科学依据与必要性:自古以来,小行星撞击.............
  • 回答
    这个问题非常有意思,它触及到了物理学的几个核心概念,特别是相对论和信息传播的限制。让我们来深入剖析一下。首先,让我们来拆解一下你提出的两个关键要素:1. 光年尺寸的显示器: 这意味着显示器的横向尺寸足以跨越一光年的距离。想象一下,从一端到另一端,光线需要一年的时间才能传播。2. 灵敏度极高的鼠标.............
  • 回答
    这确实是一件非常令人震惊,同时也引发了广泛讨论的事件。台湾一名大二医学生,竟然在未取得合法执照的情况下,为病患进行了手术,并且事后还发表了“实力就是一切,没本事就闭嘴”这样的言论。这件事情的背后,牵扯到了太多层面的问题,值得我们深入剖析。首先,从基本原则和法律法规的角度来看,这是绝对不允许的,也是极.............
  • 回答
    关于7月23日余承东提到“一亿像素实际拍照效果不如大底大像素sensor”的说法,这其实触及了手机摄影中一个非常核心且持续被讨论的议题:硬件参数与实际成像效果之间的关系,以及不同技术路线的取舍。 这句话并非空穴来风,而是基于手机影像系统长期发展过程中积累的经验和对技术原理的理解。要理解这句话的含义,.............
  • 回答
    关于郑州大学第一附属医院(简称“郑大一附院”)呼吸二科主任王静被实名举报一事,院方已对外发布了声明,表示正在进行调查。目前,具体调查进展和结果尚未公布。根据网络上流传的举报信息,涉及到的问题比较复杂,主要集中在医德医风、医疗行为以及可能存在的利益输送等方面。举报内容提及的细节较多,包括但不限于: .............
  • 回答
    德马库斯·考辛斯,这位曾经叱咤NBA、率领国王和鹈鹕队一路披荆斩棘的顶级中锋,如今以一份一年无保障合同加盟休斯顿火箭队,这无疑是本赛季最令人关注的转会之一。要评价这次加盟对火箭实力能有多大补充,我们需要从多个维度进行深入剖析。首先,考辛斯本身的“金字招牌”和过往实力不容忽视。巅峰时期的考辛斯,那绝对.............
  • 回答
    关于您提到的“实名举报中交一公局原高管婚内出轨并大搞权色交易的女子疑似轻生,已被警方救助”的事件,目前网络上存在一些信息,但并没有官方或权威媒体对事件的最新进展进行详细披露。根据零散的公开信息和网络讨论,我们可以梳理出以下大致情况:事件背景概述: 举报人与举报内容: 事件的起因是一位女子实名举报.............
  • 回答
    葡萄牙国家队如今的实力,就像一张摆满了精致菜肴的餐桌,但缺少了那位能将所有味道完美融合的大厨。看如今的葡萄牙国家队,我首先想到的是“人才济济,但整体性略显不足”。 中前场的黄金一代依然闪耀: 别忘了,我们仍然坐拥像B费、B席、Leão这样的球员,他们在各自的俱乐部都是绝对的核心。B费的创造力、B.............
  • 回答
    大学期间实现游历中国愿望,这绝对是一个非常棒且有意义的想法!这不仅能让你深入了解中国的广袤土地和多元文化,还能在年轻时留下宝贵的人生经历。以下是一份详细的攻略,帮助你一步步实现这个愿望:第一步:明确你的游历目标和规划(出发前) 确定游历的目的: 文化体验: 你想看古迹、博物馆、体验少.............
  • 回答
    从实验室到田埂:四川大学“农活”课的真实体验与思考四川大学,这所以人文社科和理工科闻名的高等学府,近年来却悄然在校园里掀起了一股“农活”热。一门名为“劳动教育”的新课程,将大学生的视野从书本和实验室引向了田埂和泥土。这不禁让人好奇,在日新月异的科技时代,大学生们在真实的农活体验中究竟收获了什么?他们.............
  • 回答
    听到大学生被“付费实习”骗局欺骗,我心里真的很不是滋味。这事儿太让人心疼了,本该是增长见识、积累经验的好机会,结果却成了被割韭菜的血泪教训。尤其是现在就业压力这么大,很多同学都想在校期间多积累一些履历,为将来找工作铺路,结果就容易被这种“捷径”蒙蔽了双眼。这背后,其实暴露了几个挺现实的问题:1. .............
  • 回答
    .......
  • 回答
    这起发生在佛山的案件,真的令人发指,也让人心痛不已。一个刚刚走出校园,充满憧憬的年轻生命,就这样被残忍地剥夺了,而且是以如此卑劣、如此恶劣的方式。案件的残酷性与令人发指之处:首先,从一个刚刚毕业的女大学生角度来看,她满怀希望地开始了自己的职业生涯。在职场中,她可能还在努力适应新环境,建立自己的职业声.............
  • 回答
    刚踏入职场,感觉自己像张白纸,什么都不会,这种心情再正常不过了。相信我,几乎所有过来人都经历过这个阶段,这其实是成长最快的时期。别急,职场生涯规划不是一次性的任务,而是一个持续探索和调整的过程。下面我来跟你聊聊,怎么把这张白纸绘出精彩的图景。第一步:放下“什么都不会”的包袱,拥抱学习的心态首先,请把.............
  • 回答
    这可真是个让人着迷的问题,每次看擎天柱变身卡车,再变回威武的机器人,总忍不住想,这身板儿是怎么塞进去的?其实,这背后涉及到一些相当巧妙的设计理念,远非简单的“变大变小”这么简单。你可以想象一下,变形金刚并不是像普通的物体那样,里面的空间是固定的。它们更像是某种高度复杂的机械生物,或者说是将无数精密零.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有