学习前提
理解INSERT、事务、类型与NULL;参数绑定由调用端API完成。
本课完成后你能做什么
让数据库拒绝无效关联与重复键,理解参数绑定边界。
先理解机制
应用验证改善反馈,数据库约束保护所有写入入口。NOT NULL禁止缺失,UNIQUE禁止重复,CHECK检查业务表达式,FOREIGN KEY约束关联。它们不能互相替代。
SQLite需要在每个连接上启用并检查foreign_keys,且应在事务开始之前设置。下面先启用,再创建表。SQLite普通表的类型亲和性不等于严格类型,因此额外检查typeof(minutes)。
外部输入应通过驱动参数绑定,例如Python连接.execute("SELECT name FROM courses WHERE id = ?", (course_id,))。占位符绑定值,不能代替表名或排序关键字;动态标识符应从明确白名单选择。
可运行示例
本系列使用SQLite 3方言。打开一个全新的内存练习数据库,例如终端执行 sqlite3 :memory:,再执行本课整段SQL。每章都自带建表和样例数据,不连接网站业务数据库。
PRAGMA foreign_keys=ON;
CREATE TABLE courses(id INTEGER PRIMARY KEY,name TEXT NOT NULL UNIQUE);
CREATE TABLE sessions(
id INTEGER PRIMARY KEY,
course_id INTEGER NOT NULL REFERENCES courses(id),
minutes INTEGER NOT NULL CHECK(typeof(minutes)='integer' AND minutes BETWEEN 0 AND 240)
);
INSERT INTO courses VALUES(1,'Python');
INSERT INTO sessions VALUES(1,1,25);
SELECT course_id,minutes FROM sessions;
推演与验证
有效记录为课程1、25分钟。单独尝试course_id=99、minutes=-1、minutes=NULL都会被约束拒绝;每项实验独立运行并观察错误。
常见错误与边界
CHECK表达式为NULL时不等同于失败,所以非空要求需要NOT NULL。约束错误之后应由应用决定并执行事务回滚策略。
动手练习
尝试再插入同名Python课程,并解释为什么不是外键错误。
参考解法与理由
INSERT INTO courses VALUES(2,'Python');违反name的UNIQUE约束。id2本身未重复,失败原因是名称唯一规则。