目录
[1. 什么是数据库约束?](#1. 什么是数据库约束?)
[2. SQLite 中的主要约束类型](#2. SQLite 中的主要约束类型)
[3. 约束详解与面试重点](#3. 约束详解与面试重点)
[3.1 PRIMARY KEY (主键约束)](#3.1 PRIMARY KEY (主键约束))
[3.2 NOT NULL (非空约束)](#3.2 NOT NULL (非空约束))
[3.3 UNIQUE (唯一约束)](#3.3 UNIQUE (唯一约束))
[3.4 FOREIGN KEY (外键约束)](#3.4 FOREIGN KEY (外键约束))
[3.5 CHECK (检查约束)](#3.5 CHECK (检查约束))
[3.6 DEFAULT (默认值约束)](#3.6 DEFAULT (默认值约束))
[4. 约束的定义级别](#4. 约束的定义级别)
1. 什么是数据库约束?
面试官提问: "你能谈谈什么是数据库约束吗?为什么我们要使用它?"
回答要点:
数据库约束(Constraints)是在表的数据列上强制执行的规则 。它们的主要目的是保证数据的完整性、准确性和可靠性。
- 
目的: - 
限制可以存储到表中的数据类型。 
- 
防止无效或"脏"数据进入数据库。 
- 
维护表与表之间的关系(参照完整性)。 
 
- 
- 
执行时机: 约束会在数据发生变化时(如 INSERT,UPDATE,DELETE)自动检查。如果操作违反了约束,该操作将被拒绝并报错。
2. SQLite 中的主要约束类型
SQLite 支持以下几种主要的约束:
- 
PRIMARY KEY(主键)
- 
NOT NULL(非空)
- 
UNIQUE(唯一)
- 
FOREIGN KEY(外键)
- 
CHECK(检查)
- 
DEFAULT(默认值)
3. 约束详解与面试重点
3.1 PRIMARY KEY (主键约束)
- 
定义: 用于唯一标识表中的每一行。 
- 
特性: - 
它隐含了 UNIQUE和NOT NULL两个约束。
- 
一张表最多只能有一个主键。 
- 
主键可以是单列,也可以是多列(称为"复合主键")。 
 
- 
- 
示例: -- 单列主键 CREATE TABLE Users ( user_id INTEGER PRIMARY KEY, -- 隐含 UNIQUE 和 NOT NULL username TEXT ); -- 复合主键 (表级定义) CREATE TABLE OrderDetails ( order_id INTEGER, product_id INTEGER, quantity INTEGER, PRIMARY KEY (order_id, product_id) );
- 
⭐ SQLite 面试重点: INTEGER PRIMARY KEY与ROWID- 
在 SQLite 中,几乎所有的表都有一个隐藏的、唯一的64位有符号整数列,名为 ROWID。
- 
如果你将一列定义为 INTEGER PRIMARY KEY(必须是INTEGER,不能是INT或BIGINT),那么这一列实际上会成为ROWID的别名。
- 
好处: 这是 SQLite 中最高效的主键类型,因为它直接使用了底层的 ROWID进行查找,速度极快。
- 
对比: 如果你定义 user_id TEXT PRIMARY KEY,SQLite 会为user_id单独创建一个索引,并且仍然在内部维护一个ROWID。
 
- 
- 
⭐ SQLite 面试重点: AUTOINCREMENT关键字- 
误区: 很多人认为 INTEGER PRIMARY KEY就会自动增长。它确实会自动生成一个唯一的 ID,但它可能重用之前删除过的行的 ID。
- 
AUTOINCREMENT的真正作用: 当你使用INTEGER PRIMARY KEY AUTOINCREMENT时,SQLite 会保证 新插入的 ID 永远大于 该表中曾经存在过的任何 ID。即使你删除了 ID 最大的行,下一个 ID 也会继续增长,绝不重用。
- 
代价: AUTOINCREMENT会带来额外的 CPU、内存和磁盘开销,因为它需要一个额外的sqlite_sequence表来跟踪每个表的最大 ID。
- 
面试结论: 除非你明确需要"ID 永不重用"的特性,否则只使用 INTEGER PRIMARY KEY是最高效的选择。-- 推荐的高效方式 (可能会重用已删除的ID) 
 CREATE TABLE Logs (
 log_id INTEGER PRIMARY KEY,
 message TEXT
 );-- 保证ID永不重用 (开销稍大) 
 CREATE TABLE Invoices (
 invoice_id INTEGER PRIMARY KEY AUTOINCREMENT,
 amount REAL
 );
 
- 
3.2 NOT NULL (非空约束)
- 
定义: 确保该列的值永远不能为 NULL。
- 
示例: CREATE TABLE Products ( product_id INTEGER PRIMARY KEY, name TEXT NOT NULL, -- 商品名不能为空 price REAL NOT NULL -- 价格不能为空 ); -- 尝试插入 NULL 将会失败 INSERT INTO Products (name, price) VALUES (NULL, 9.99); -- 错误!
3.3 UNIQUE (唯一约束)
- 
定义: 确保该列(或多列组合)中的所有值都是唯一的。 
- 
特性: - 
与 PRIMARY KEY类似,但UNIQUE约束允许NULL值。
- 
⭐ SQLite 面试重点: 在 UNIQUE约束的列中,你可以存储多个NULL值 。SQLite (以及 PostgreSQL) 认为NULL不等于NULL,所以多个NULL并不违反唯一性。 (注意:这在 SQL Server 或 Oracle 中行为不同)。
- 
一张表可以有多个 UNIQUE约束。
 
- 
- 
示例: CREATE TABLE Employees ( emp_id INTEGER PRIMARY KEY, ssn TEXT UNIQUE, -- 社保号必须唯一 (但允许有人没有社保号, 即 NULL) email TEXT UNIQUE -- 邮箱也必须唯一 ); -- 以下插入在 SQLite 中是允许的 INSERT INTO Employees (ssn) VALUES (NULL); INSERT INTO Employees (ssn) VALUES (NULL); -- 再次插入 NULL,仍然允许
3.4 FOREIGN KEY (外键约束)
- 
定义: 用于在两个表之间建立连接并强制实现参照完整性。 
- 
工作原理: - 它指定一个(或一组)列,称为"子列",其值必须在另一张表("父表")的 PRIMARY KEY或UNIQUE列中存在,或者为NULL。
 
- 它指定一个(或一组)列,称为"子列",其值必须在另一张表("父表")的 
- 
示例: -- 1. 创建父表 (Departments) CREATE TABLE Departments ( dept_id INTEGER PRIMARY KEY, dept_name TEXT NOT NULL ); -- 2. 创建子表 (Employees) CREATE TABLE Employees ( emp_id INTEGER PRIMARY KEY, name TEXT, dept_id INTEGER, -- 这是外键列 FOREIGN KEY (dept_id) REFERENCES Departments (dept_id) ON DELETE SET NULL -- 如果父表部门被删除,员工的部门设为NULL ON UPDATE CASCADE -- 如果父表部门ID更新,员工的部门ID也跟着更新 );
- 
外键动作 ( ON DELETE/ON UPDATE):- 
NO ACTION/RESTRICT(默认):如果子表存在关联数据,禁止删除/更新父表。
- 
SET NULL:父表数据变化时,子表对应列设为NULL。
- 
SET DEFAULT:父表数据变化时,子表对应列设为默认值。
- 
CASCADE:父表数据删除/更新时,子表关联的行也级联删除/更新。
 
- 
- 
⭐ SQLite 面试重点:启用外键 - 
在旧版本的 SQLite 中,外键支持默认是关闭的。在现代版本中(3.6.19 之后),通常在编译时默认开启。 
- 
但为了保证兼容性和安全性,在建立连接后立即执行 PRAGMA foreign_keys = ON;是一个非常好的习惯,这在面试中是加分项。-- 在你的应用程序连接数据库后,应首先执行这个命令 
 PRAGMA foreign_keys = ON;
 
- 
3.5 CHECK (检查约束)
- 
定义: 允许你指定一个布尔表达式, INSERT或UPDATE的数据必须满足该表达式(即表达式结果为TRUE)才能被写入。
- 
特性: SQLite 支持 CHECK约束(但 MySQL 长期忽略它,直到 8.0)。
- 
示例: CREATE TABLE Products ( id INTEGER PRIMARY KEY, name TEXT, price REAL CHECK (price > 0), -- 价格必须大于0 discount REAL, -- 表级 CHECK 约束,可以引用多列 CHECK (discount < price) -- 折扣必须小于价格 );
3.6 DEFAULT (默认值约束)
- 
定义: 当 INSERT语句没有为该列提供值时,自动为其分配一个默认值。
- 
示例: CREATE TABLE Orders ( order_id INTEGER PRIMARY KEY, order_date TEXT DEFAULT (DATE('now')), -- 使用函数作为默认值 status TEXT DEFAULT 'Pending' -- 使用常量作为默认值 ); -- 插入时,可以不指定 order_date 和 status INSERT INTO Orders (order_id) VALUES (101); -- 数据库中该行将自动填充 (..., '2025-10-29', 'Pending')
4. 约束的定义级别
约束可以在两个级别上定义:
- 
列级约束 (Column-level): - 
作为列定义的一部分。 
- 
NOT NULL只能在列级定义。
- 
适用于: NOT NULL,PRIMARY KEY,UNIQUE,CHECK,DEFAULT,FOREIGN KEY(单列)。CREATE TABLE Example ( 
 id INTEGER PRIMARY KEY,
 email TEXT UNIQUE NOT NULL CHECK (length(email) > 5)
 );
 
- 
- 
表级约束 (Table-level): - 
在所有列定义之后,单独定义。 
- 
必须用于定义"复合主键"或"复合唯一/外键" (即约束涉及多于一列)。 
- 
适用于: PRIMARY KEY,UNIQUE,CHECK,FOREIGN KEY。CREATE TABLE Example ( 
 col1 INTEGER,
 col2 INTEGER,
 col3 TEXT,-- 表级定义 PRIMARY KEY (col1, col2), UNIQUE (col2, col3)); 
 
-