当前位置: 首页 > news >正文

MySQL表约束体系全解:从基础语法到实战设计,吃透所有约束类型与核心坑点

前言

在MySQL中,数据类型是对字段存储格式的第一层约束,但仅靠数据类型无法保障数据的业务合法性与完整性。比如用户邮箱必须唯一、用户姓名不能为空、订单所属用户必须在用户表中存在……这些业务层面的规则,都需要通过表的约束来实现。

表约束是MySQL在数据写入层面的最后一道校验关卡,能够从数据库层面强制保证数据的正确性、一致性和完整性。本文将系统讲解MySQL中所有常用约束的语法、原理、实战场景与常见坑点,帮助你从“会写”到“懂原理”,设计出健壮的数据库表结构。

一、约束的概念与分类

1.1 什么是约束

约束是作用于表中字段上的规则,用于限制存储在表中的数据类型、取值范围、唯一性等特性。如果插入/修改的数据违反了约束规则,操作会被直接拒绝,从而保证数据库中数据的正确性和可靠性。

1.2 常用约束类型总览

我们可以把MySQL常用约束分为几大类:

约束类型关键字核心作用
非空约束NOT NULL限制该字段值不能为NULL
默认值约束DEFAULT字段未赋值时,自动使用默认值
注释约束COMMENT给字段添加业务描述,便于维护
零填充约束ZEROFILL数值显示时自动补前导零,仅影响显示格式
主键约束PRIMARY KEY唯一标识一行数据,非空且唯一,一张表只能有一个
自增长约束AUTO_INCREMENT数值字段自动递增,常配合主键使用
唯一约束UNIQUE KEY保证字段值在表中唯一,允许为NULL
外键约束FOREIGN KEY建立两表关联,保证数据引用的一致性

二、非空约束(NOT NULL)

2.1 基本概念

非空约束用于限制字段的值不能为NULL。MySQL默认所有字段都允许为NULL(即默认是NULL属性),但在实际开发中,绝大多数业务字段都应该设置为NOT NULL

2.2 为什么要尽量避免NULL?

很多新手觉得NULL和空值没区别,这是最大的误区。NULL在MySQL中是一个特殊值,会带来很多问题:

  1. 运算结果不可控:任何数值与NULL进行运算,结果都是NULL
SELECT1+NULL;-- 结果为NULLSELECTCONCAT('hello',NULL);-- 结果为NULL
  1. 统计结果偏差COUNT(字段名)会自动忽略值为NULL的行,导致统计数据不准
-- 若name字段有一行NULLSELECTCOUNT(*)FROMuser;-- 统计总行数,包含NULL行SELECTCOUNT(name)FROMuser;-- 统计name非空的行数,不包含NULL行
  1. 查询逻辑失效:不能用= NULL判断空值,必须用IS NULL/IS NOT NULL= NULL永远返回false

2.3 语法与实战示例

创建表时直接在字段后加NOT NULL即可:

-- 创建班级表:班级名和教室都不允许为空CREATETABLEmy_class(class_nameVARCHAR(20)NOTNULLCOMMENT'班级名称',class_roomVARCHAR(10)NOTNULLCOMMENT'教室编号')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

如果插入时不给非空字段赋值,会直接报错:

INSERTINTOmy_class(class_name)VALUES('计算机1班');-- 报错:ERROR 1364 (HY000): Field 'class_room' doesn't have a default value

2.4 易错点提醒

  • ❌ 误区:空字符串''等于NULL
    ✅ 事实:空字符串是一个长度为0的有效字符串,不属于NULL;NOT NULL约束允许插入空字符串。
  • ❌ 误区:所有字段都没必要加NOT NULL
    ✅ 事实:除了明确允许为空的业务字段(比如用户的可选备注信息),其余字段都建议设置NOT NULL,避免NULL带来的各种异常。

三、默认值约束(DEFAULT)

3.1 基本概念

当插入数据时,如果没有给该字段赋值,就会自动使用DEFAULT指定的默认值。默认值约束可以大幅减少插入语句的冗余,同时配合NOT NULL保证字段非空。

3.2 语法与实战示例

CREATETABLEuser_info(idINTPRIMARYKEYAUTO_INCREMENTCOMMENT'用户ID',nameVARCHAR(20)NOTNULLCOMMENT'用户名',ageTINYINTUNSIGNEDNOTNULLDEFAULT0COMMENT'年龄,默认0',sexCHAR(2)NOTNULLDEFAULT'男'COMMENT'性别,默认男',create_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间,默认当前时间')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

插入时省略带默认值的字段,自动填充默认值:

-- 只插入name字段,age、sex、create_time自动使用默认值INSERTINTOuser_info(name)VALUES('张三');-- 查询验证SELECT*FROMuser_info;

3.3 重点补充:常用默认值场景

  • 数值型字段:默认0,比如状态、数量、年龄
  • 字符串字段:默认''空字符串,避免NULL
  • 时间字段:DEFAULT CURRENT_TIMESTAMP记录创建时间,ON UPDATE CURRENT_TIMESTAMP自动记录更新时间(开发高频使用)
    update_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间'

3.4 易错点提醒

  • ❌ 误区:设置了DEFAULT的字段就不用加NOT NULL了
    ✅ 事实:DEFAULT只在“插入时不赋值”时生效,如果显式插入NULL,依然会写入NULL。因此规范写法是NOT NULL DEFAULT xxx,既保证默认值,又禁止显式插入NULL。
  • ❌ 误区:默认值只能是常量
    ✅ 事实:时间类型可以使用CURRENT_TIMESTAMP等函数,但普通字段不能直接用函数生成默认值。

四、列描述注释(COMMENT)

4.1 基本概念

COMMENT是字段的注释说明,不会影响数据存储和约束逻辑,专门用来描述字段的业务含义,方便后续开发和DBA维护表结构。企业级开发规范要求:所有表和所有字段都必须加COMMENT

4.2 查看注释的两种方式

  1. 查看建表语句(最常用)
SHOWCREATETABLEuser_info\G

执行后会显示完整的建表SQL,包含所有字段的COMMENT。

  1. 从系统表查询(适合批量获取)
SELECTCOLUMN_NAME'字段名',COLUMN_COMMENT'字段注释'FROMinformation_schema.COLUMNSWHERETABLE_SCHEMA='你的数据库名'ANDTABLE_NAME='user_info';

4.3 易错点提醒

  • DESC 表名命令无法查看字段注释,只能通过上面两种方式查看。
  • 注释不属于强制约束,但属于开发规范,是表可维护性的关键。

五、零填充约束(ZEROFILL)

5.1 基本概念

ZEROFILL是数值型字段的显示格式约束:当数值的位数小于字段定义的显示宽度时,自动在左侧补0。

注意:ZEROFILL只影响查询显示的格式,不影响实际存储的值,数据库内部存储的依然是原始数值。

5.2 核心原理:int(M)的真正含义

很多新手会疑惑int(5)int(11)有什么区别,是不是存储范围不一样?
答案是:没有ZEROFILL时,括号里的数字没有任何意义,int类型的存储范围永远是4字节(-2147483648~2147483647)。
括号里的M叫做“显示宽度”,只有配合ZEROFILL时才会生效,用来指定补零后的总位数。

5.3 实战示例

CREATETABLEtest_zerofill(aINT(5)ZEROFILLCOMMENT'5位宽度零填充',bINT(10)COMMENT'无零填充')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;-- 插入数据INSERTINTOtest_zerofillVALUES(1,2);-- 查询查看效果SELECT*FROMtest_zerofill;

查询结果:

ab
000012

我们可以用HEX函数验证存储的真实值:

SELECTa,HEX(a)FROMtest_zerofill;

结果显示HEX(a)为1,证明内部存储的就是数值1,00001只是显示格式化的效果。

5.4 易错点提醒

  1. ZEROFILL会自动添加UNSIGNED属性:因为负数没有前导零的意义,所以设置ZEROFILL后,字段自动变为无符号整型。
  2. 仅适用于数值型字段,实际开发中使用场景很少,多用于固定长度的编号(比如订单号、学号)。

六、主键约束(PRIMARY KEY)

6.1 核心概念

主键是表中一行数据的唯一标识,具备两个核心特性:

  • 非空:主键字段的值不能为NULL
  • 唯一:主键字段的值不能重复

一张表最多只能有一个主键(可以是多个字段组成的复合主键)。
从索引角度看,主键对应的是聚簇索引,数据在磁盘上就是按照主键顺序存储的,因此主键查询效率是最高的。

6.2 单字段主键

创建表时直接在字段后加PRIMARY KEY即可:

CREATETABLEstudent(idINTUNSIGNEDPRIMARYKEYCOMMENT'学号,主键',nameVARCHAR(20)NOTNULLCOMMENT'姓名')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

插入重复主键会直接报错:

INSERTINTOstudentVALUES(1,'张三');INSERTINTOstudentVALUES(1,'李四');-- 报错:ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

6.3 复合主键

由多个字段共同组成一个主键,多个字段组合起来不能重复,单个字段可以重复。多用于多对多中间表、联合主键场景。

语法:在所有字段定义完成后,用PRIMARY KEY(字段1, 字段2)指定

-- 学生成绩表:学号+课程号作为复合主键CREATETABLEstudent_score(student_idINTUNSIGNEDNOTNULLCOMMENT'学号',course_idCHAR(10)NOTNULLCOMMENT'课程号',scoreTINYINTUNSIGNEDDEFAULT60COMMENT'成绩',PRIMARYKEY(student_id,course_id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

复合主键的规则:两个字段的值完全相同时才算冲突,单个字段重复是允许的。

INSERTINTOstudent_scoreVALUES(1,'C001',90);INSERTINTOstudent_scoreVALUES(1,'C002',85);-- 正常,学号重复,课程号不同INSERTINTOstudent_scoreVALUES(2,'C001',95);-- 正常,课程号重复,学号不同INSERTINTOstudent_scoreVALUES(1,'C001',88);-- 报错,组合重复

6.4 主键的增删改

表创建完成后,也可以通过ALTER语句追加或删除主键:

  1. 追加主键
-- 给无主键的表添加主键ALTERTABLEstudentADDPRIMARYKEY(id);
  1. 删除主键
ALTERTABLEstudentDROPPRIMARYKEY;

6.5 主键设计最佳实践

企业级开发中,主键设计遵循一个核心原则:使用与业务无关的代理主键,不使用业务字段作为主键

  • 比如不要用身份证号、手机号、工号作为主键,因为业务字段可能会随着业务调整而变化,主键修改的成本极高。
  • 推荐使用自增INT、BIGINT或者雪花ID作为主键,和业务完全解耦。

6.6 易错点提醒

  • ❌ 误区:一张表可以有多个主键
    ✅ 事实:一张表只能有一个主键,但可以是多字段组成的复合主键。
  • ❌ 误区:删除主键直接DROP就行
    ✅ 事实:如果主键字段有AUTO_INCREMENT属性,必须先去掉自增长属性,才能删除主键,否则会报错。

七、自增长约束(AUTO_INCREMENT)

7.1 基本概念

自增长约束作用于数值型字段,当插入数据不给该字段赋值时,系统会自动从当前最大值+1生成一个新值。通常和主键搭配使用,作为逻辑主键。

7.2 基本语法

CREATETABLEuser(idINTUNSIGNEDPRIMARYKEYAUTO_INCREMENTCOMMENT'用户ID,自增主键',usernameVARCHAR(20)NOTNULLCOMMENT'用户名')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

插入数据时,自增字段可以赋值为NULL或者省略,自动递增:

INSERTINTOuser(username)VALUES('user1');INSERTINTOuser(username)VALUES('user2');SELECT*FROMuser;-- id自动变成1、2

7.3 获取最后插入的自增ID

插入数据后,可以通过LAST_INSERT_ID()函数获取本次连接最后插入的自增ID:

SELECTLAST_INSERT_ID();

注意:该函数是连接级别的,不同连接之间互不影响;批量插入时,返回的是第一条数据的自增ID。

7.4 深度解析:自增长的特性与坑点

  1. 自增长的前提条件

    • 字段必须是索引(主键或唯一键)
    • 字段必须是整数类型(TINYINT、INT、BIGINT等)
    • 一张表最多只能有一个自增长字段
  2. 自增长不连续的场景(高频面试题)
    自增长值一旦被消耗就不会回退,以下场景会出现ID不连续:

    • 插入数据失败/唯一键冲突,自增值已经被消耗
    • 事务回滚,自增值不会回滚
    • 批量插入数据时,会预分配自增值,多余的会被丢弃
    • 数据库重启(InnoDB的自增值在内存中,重启后会重新计算)
  3. 自定义初始值和步长
    可以通过修改变量调整自增长的起始值和步长(多用于主主架构):

    -- 设置自增步长为2SET@@auto_increment_increment=2;-- 设置自增起始偏移量为1SET@@auto_increment_offset=1;

7.5 易错点提醒

  • ❌ 误区:自增长一定是从1开始连续递增
    ✅ 事实:自增长只能保证递增,不能保证连续,不要依赖自增ID的连续性做业务逻辑。
  • ❌ 误区:自增长字段不能手动赋值
    ✅ 事实:可以手动赋值,只要不重复就行,后续自增会从手动插入的最大值开始+1。

八、唯一键约束(UNIQUE KEY)

8.1 基本概念

唯一键约束保证字段的值在表中不能重复,解决了“一张表只能有一个主键,但有多个字段需要保证唯一性”的问题。比如用户表中,手机号、邮箱、身份证号都需要唯一,这时候就可以用唯一键。

8.2 基本语法

CREATETABLEuser(idINTPRIMARYKEYAUTO_INCREMENTCOMMENT'主键ID',usernameVARCHAR(20)NOTNULLCOMMENT'用户名',emailVARCHAR(64)UNIQUECOMMENT'邮箱,唯一',phoneCHAR(11)UNIQUEKEYCOMMENT'手机号,唯一')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

插入重复值会报错:

INSERTINTOuser(username,email)VALUES('张三','zhangsan@test.com');INSERTINTOuser(username,email)VALUES('李四','zhangsan@test.com');-- 报错:ERROR 1062 (23000): Duplicate entry 'zhangsan@test.com' for key 'email'

8.3 联合唯一键

和复合主键类似,多个字段组合起来保证唯一:

-- 用户收藏表:同一个用户不能重复收藏同一个商品CREATETABLEuser_collect(idINTPRIMARYKEYAUTO_INCREMENT,user_idINTNOTNULL,goods_idINTNOTNULL,UNIQUEKEYuk_user_goods(user_id,goods_id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

8.4 核心特性:NULL值的处理

唯一键允许字段值为NULL,并且多个NULL值不会冲突
因为在MySQL中,NULL和任何值都不相等,包括NULL本身,所以多条数据的唯一键字段为NULL时,不会触发唯一约束冲突。

INSERTINTOuser(username,email)VALUES('王五',NULL);INSERTINTOuser(username,email)VALUES('赵六',NULL);-- 执行成功,两个NULL不会冲突

8.5 主键 vs 唯一键 核心区别

对比维度主键 PRIMARY KEY唯一键 UNIQUE KEY
数量限制一张表只能有一个一张表可以有多个
NULL值不允许为NULL允许为NULL,且多个NULL不冲突
索引类型聚簇索引非聚簇唯一索引
作用唯一标识一行数据保证业务字段不重复
设计原则用无业务含义的代理主键作用于有唯一性要求的业务字段

8.6 易错点提醒

  • ❌ 误区:唯一键不能有NULL值
    ✅ 事实:唯一键允许多个NULL值,这是和主键最核心的区别之一。
  • ❌ 误区:UNIQUEUNIQUE KEY不一样
    ✅ 事实:两者语法完全等价,没有区别。

九、外键约束(FOREIGN KEY)

9.1 基本概念

外键用于建立两张表之间的关联关系,保证从表的外键字段值,必须在主表的主键/唯一键中存在,或者为NULL。从而保证数据引用的一致性,避免脏数据。

  • 主表(父表):被引用的表,必须有主键或唯一键
  • 从表(子表):设置外键的表,外键字段引用主表的主键/唯一键

9.2 基本语法

语法:FOREIGN KEY (从表字段) REFERENCES 主表(主表字段)

示例:班级表(主表)和学生表(从表)

  1. 先创建主表(班级表)
CREATETABLEclass(idINTPRIMARYKEYCOMMENT'班级ID',class_nameVARCHAR(30)NOTNULLCOMMENT'班级名称')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;
  1. 再创建从表(学生表),设置外键关联班级表
CREATETABLEstudent(idINTPRIMARYKEYCOMMENT'学生ID',nameVARCHAR(30)NOTNULLCOMMENT'学生姓名',class_idINTCOMMENT'所属班级ID',-- 外键约束:class_id 引用 class表的id字段FOREIGNKEY(class_id)REFERENCESclass(id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

9.3 约束效果验证

  1. 正常插入:先插入主表数据,再插入从表数据
INSERTINTOclassVALUES(10,'Java班'),(20,'C++班');INSERTINTOstudentVALUES(1001,'张三',10),(1002,'李四',20);
  1. 插入不存在的班级ID,直接报错
INSERTINTOstudentVALUES(1003,'王五',30);-- 报错:ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
  1. 外键字段可以为NULL(未分配班级的学生)
INSERTINTOstudentVALUES(1003,'王五',NULL);-- 执行成功

9.4 补充:外键的级联操作

基础外键默认是限制模式:主表的记录被从表引用时,无法直接删除/修改主表记录。通过设置级联行为,可以定义主表数据变更时,从表的处理逻辑:

级联行为说明
ON DELETE CASCADE删除主表记录时,自动删除从表中关联的记录
ON UPDATE CASCADE更新主表主键时,自动更新从表中关联的外键值
ON DELETE SET NULL删除主表记录时,将从表关联的外键值设为NULL
ON DELETE RESTRICT默认值,限制删除,有从表关联时禁止删除主表记录

示例:带级联删除和级联更新的外键

CREATETABLEstudent(idINTPRIMARYKEYCOMMENT'学生ID',nameVARCHAR(30)NOTNULLCOMMENT'学生姓名',class_idINTCOMMENT'所属班级ID',FOREIGNKEY(class_id)REFERENCESclass(id)ONDELETECASCADEONUPDATECASCADE)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

9.5 深度讨论:物理外键 vs 逻辑外键

虽然外键能保证数据一致性,但在互联网大厂的开发规范中,普遍不推荐使用物理外键(数据库层面的FOREIGN KEY),而是使用逻辑外键(应用层维护关联关系),原因如下:

  1. 性能影响:每次写入数据都要校验外键,高并发下性能差,影响数据库扩展性
  2. 维护困难:分库分表场景下,外键完全无法使用
  3. 耦合度高:表之间强耦合,后续业务调整、数据迁移成本高
  4. 级联风险:级联删除可能导致误删大量数据,引发生产事故

建议:小项目、内部系统可以用物理外键保证数据安全;高并发、大型系统推荐使用逻辑外键,在应用层保证数据一致性。

9.6 易错点提醒

  1. 存储引擎限制:只有InnoDB引擎支持外键,MyISAM引擎不支持外键约束(即使写了FOREIGN KEY语法也不会生效)。
  2. 主表字段要求:主表被引用的字段,必须是主键或者唯一键,否则无法创建外键。
  3. 字段类型一致:从表外键字段和主表被引用字段的类型、长度、字符集必须完全一致,否则创建失败。

十、综合实战:电商商城表设计

我们通过一个经典的电商场景,综合运用所有约束,设计三张表:商品表、用户表、订单表。

需求说明

  1. 商品表:商品ID主键自增,商品名称非空,单价非空默认0,分类、供应商非空
  2. 用户表:用户ID主键自增,用户名非空,邮箱唯一,手机号唯一,性别非空
  3. 订单表:订单ID主键自增,用户ID关联用户表,商品ID关联商品表,购买数量默认1

完整建表SQL

-- 创建数据库CREATEDATABASEIFNOTEXISTSshop_mallDEFAULTCHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;USEshop_mall;-- 1. 商品表CREATETABLEIFNOTEXISTSgoods(goods_idINTPRIMARYKEYAUTO_INCREMENTCOMMENT'商品ID,主键',goods_nameVARCHAR(64)NOTNULLCOMMENT'商品名称',unit_priceINTNOTNULLDEFAULT0COMMENT'单价,单位:分',categoryVARCHAR(32)NOTNULLCOMMENT'商品分类',providerVARCHAR(64)NOTNULLCOMMENT'供应商名称',create_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT'商品表';-- 2. 用户表CREATETABLEIFNOTEXISTScustomer(customer_idINTPRIMARYKEYAUTO_INCREMENTCOMMENT'用户ID,主键',usernameVARCHAR(32)NOTNULLCOMMENT'用户名',emailVARCHAR(64)UNIQUECOMMENT'邮箱,唯一',phoneCHAR(11)NOTNULLUNIQUECOMMENT'手机号,唯一非空',sexENUM('男','女','保密')NOTNULLDEFAULT'保密'COMMENT'性别',id_cardCHAR(18)UNIQUECOMMENT'身份证号,唯一',addressVARCHAR(256)DEFAULT''COMMENT'收货地址',register_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'注册时间')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT'客户表';-- 3. 订单表CREATETABLEIFNOTEXISTSpurchase(order_idINTPRIMARYKEYAUTO_INCREMENTCOMMENT'订单ID,主键',customer_idINTNOTNULLCOMMENT'下单用户ID',goods_idINTNOTNULLCOMMENT'购买商品ID',numsINTNOTNULLDEFAULT1COMMENT'购买数量',order_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'下单时间',-- 逻辑外键,不创建物理外键约束,应用层维护INDEXidx_customer_id(customer_id),INDEXidx_goods_id(goods_id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT'购买订单表';

设计说明

  • 所有表和字段都加了COMMENT,符合企业开发规范
  • 核心业务字段都设置了NOT NULL+DEFAULT,避免NULL值带来的异常
  • 邮箱、手机号、身份证号用唯一键保证业务唯一性
  • 订单表没有创建物理外键,而是加了普通索引提升查询效率,符合互联网开发规范
  • 时间字段都设置了默认当前时间,减少插入代码冗余

十一、常见易错点汇总

  1. NULL相关坑:NULL参与运算结果为NULL,count(字段)忽略NULL,不能用=NULL判断
  2. int(M)误解:M是显示宽度,不影响存储范围,只有配合ZEROFILL才有用
  3. ZEROFILL隐式转换:设置ZEROFILL自动变为无符号整型
  4. 主键数量限制:一张表只能一个主键,可以是复合主键
  5. 自增长不连续:插入失败、事务回滚都会导致自增ID空洞,不要依赖连续性
  6. 唯一键NULL特性:唯一键允许多个NULL,不会冲突
  7. 外键引擎限制:只有InnoDB支持外键,MyISAM不生效
  8. 外键字段类型:主从表关联字段类型必须完全一致

十二、总结

MySQL的表约束是数据完整性的基石,不同约束有不同的适用场景:

  • 基础约束(NOT NULL、DEFAULT、COMMENT):属于开发规范,建议所有表都合理使用
  • 主键+自增长:是绝大多数表的标准配置,优先使用代理主键
  • 唯一键:用于业务字段的唯一性校验,注意NULL值特性
  • 外键:根据项目场景选择,小型系统可用物理外键,高并发系统推荐逻辑外键

合理设计表约束,能够在数据库层面提前拦截非法数据,大幅降低业务代码的校验成本,同时提升数据的一致性和可维护性。

如果觉得本文对你有帮助,欢迎点赞、收藏、评论交流~🎉

http://www.jsqmd.com/news/1002245/

相关文章:

  • MiniCPM-o 2.6:性能媲美GPT-4o,轻松玩转AI多模态直播与语音识别!
  • Transformer:现代大模型核心架构入门
  • Rust周刊2026W23 | Rust基金会维护者基金、halloy 2026.7、Zstandard Rust实现、Roto一周年、gRPC-Rust路线图
  • 智能体时代的产品经理如何转型
  • GEE新手避坑指南:获取MODIS NDVI数据时,为什么你的值域总是不对?
  • Java毕设项目: 基于 SpringBoot 的医疗机构就诊服务管理系统的设计与实现(源码+文档,讲解、调试运行,定制等)
  • 别再手动改文献了!用Better BibTex插件5分钟搞定Zotero导出格式,完美对齐Google Scholar
  • 别再让三坐标测量机闲着!NETDMIS5.0脱机编程实战:从CAD导入到虚拟找正,一次搞定
  • GPT-4参数量与稀疏激活真相:1.8万亿参数和2% per token的工程本质
  • 色弱的人
  • 细说RocketMQ双网卡问题
  • i.MX21架构解析:异构计算与低功耗设计如何重塑嵌入式多媒体
  • 用Arduino UNO和ULN2003驱动28BYJ-48步进电机,手把手教你做个迷你云台
  • PrivAct框架:多智能体协同的LLM隐私保护方案
  • VMware Workstation Pro 17 虚拟化技术指南:许可证管理与企业级部署方案
  • 5G NR HARQ配置避坑指南:异步、自适应参数怎么调?
  • 线程管理特点 线程属性 线程状态之间切换
  • 别再只会用装饰器了!用Python Hook机制给你的Flask/Django应用加个‘插件’功能
  • PVZ Toolkit技术架构解析:内存注入与跨版本兼容性实现
  • 组件库版本管理与语义化发布:从手动发包到自动化交付链路
  • 3大核心技术揭秘:ComfyUI-Easy-Use如何实现GPU资源高效释放
  • 数字信号控制器DSC:融合DSP与MCU优势,实现电机驱动与实时控制
  • 2026年浙江牛皮纸扑克牌源头厂家专业实力与选型全解析 - 品牌鉴赏官2026
  • 用STM32CubeMX给SD卡做个“体检”:手把手教你读取CID/CSD信息并计算容量(SPI+FATFS)
  • 手把手教你给i.MX RT1021核心板刷入MicroPython(附LCD驱动配置)
  • 终极免费Flash逆向工具:如何用JPEXS解构失落的SWF遗产
  • HP 3457A万用表Python自动化工具:GPIB控制+实时曲线+出厂精度比对
  • Fast-GitHub:彻底解决国内GitHub访问慢的创新技术方案
  • 电缆故障定位仪:实战选型、技术解析与效率提升指南
  • NSK LH65EL 导轨滑块升级及参数详解