MySQL 简介

常用数据类型与约束

掌握 MySQL 常用数据类型的选型思路和常用约束,能设计出结构合理的表。

🎯 引言

前面我们已经会建表和查询了,但建表时每个字段后面跟的 INTVARCHAR 到底该怎么选?选错了会有什么后果?学完这篇文章,你能说清楚常用数据类型的区别和适用场景,会用约束给表加上「防护规则」,并独立设计出一张结构合理的用户表。


🧱 数值类型:INT 与 DECIMAL

整数最常用的就是 INT,大约能存正负 21 亿,存用户 ID、年龄、库存都够用。

小数方面,MySQL 提供 FLOATDOUBLEDECIMAL 三种。这里有一个重要的坑:FLOAT 和 DOUBLE 是浮点数,存在精度误差

你在 JS 里可能遇到过 0.1 + 0.2 不等于 0.3,而是 0.30000000000000004。这是二进制浮点数的通病,MySQL 的 FLOAT 也一样。如果只是展示温度、评分,这点误差不影响;但金额差一分钱都是事故,所以涉及钱的字段一律用 DECIMAL,它按十进制精确存储。

CREATE TABLE account (
    id INT PRIMARY KEY,
    balance DECIMAL(10, 2)
);

DECIMAL(10, 2) 表示一共 10 位数字,其中 2 位是小数,也就是最大能存 99999999.99

记忆口诀:整数用 INT,金额用 DECIMAL,能容忍误差的统计类小数才考虑 FLOAT 或 DOUBLE。

⚡ 字符串类型:CHAR、VARCHAR 与 TEXT

CHAR 是定长字符串CHAR(11) 不管你存几个字,都按 11 个字符占位,适合长度固定的数据,比如手机号、MD5 值。

VARCHAR 是变长字符串VARCHAR(50) 存多长占多长,只在尾部多记 1 到 2 个字节的长度信息。用户名、邮箱、标题这类长度不一的字段都用它。

可以打个比喻:CHAR 像固定大小的快递纸箱,不管装什么都占那么大地方;VARCHAR 像可伸缩的袋子,装多少占多少。

TEXT 用于长文本,比如文章内容、商品详情,能存几万字符。但它不适合做条件查询和索引,所以「经常要拿来搜索的字段」不要用 TEXT。

CREATE TABLE note (
    id INT PRIMARY KEY,
    title VARCHAR(100),
    content TEXT
);

🧰 日期时间类型:DATE、DATETIME 与 TIMESTAMP

  • DATE:只存日期,格式 2026-07-20,适合生日、节假日这类不需要时间的场景。
  • DATETIME:存日期加时间,格式 2026-07-20 10:30:00,范围大(到 9999 年),适合注册时间、订单时间等业务时间。
  • TIMESTAMP:也存日期加时间,但内部会跟随时区转换,范围只到 2038 年。它适合记录「数据变动的时刻」,比如更新时间。

日常开发中,业务时间字段(注册时间、创建时间)用 DATETIME 是常见选择,简单直观、不受 2038 年限制。

SELECT NOW(), CURDATE(), CURTIME();

这条语句能查看当前的完整时间、日期和时刻,在插入数据时也常用 NOW() 自动填当前时间。执行结果如下(示例,实际以你执行时的时间为准):

NOW()CURDATE()CURTIME()
2026-07-20 10:30:002026-07-2010:30:00

💡 布尔值:用 TINYINT(1)

MySQL 没有真正的布尔类型,约定用 TINYINT(1) 表示:1 代表真,0 代表假。

比如用户表里标记是否会员、是否删除(软删除),都是典型用法:

is_member TINYINT(1) DEFAULT 0

虽然 MySQL 也认识 BOOLEAN 关键字,但它只是 TINYINT(1) 的别名,两者完全一样。


🛠 常用约束:给表加防护规则

约束是建表时声明的规则,MySQL 会在写入数据时自动检查,不满足就拒绝。这就像小区门口的保安,不合格的数据根本进不了库,比在代码里到处写校验可靠得多。

常用的有这几个:

  • PRIMARY KEY:主键,唯一标识每一行,一张表通常有一个,不能重复也不能为空。
  • AUTO_INCREMENT:自增,配合主键使用,插入时不用手动给 ID,MySQL 自动 +1。
  • NOT NULL:非空,该字段必须填,防止插入缺斤少两的数据。
  • UNIQUE:唯一,同一个值只能出现一次,比如用户名不能撞车。
  • DEFAULT:默认值,插入时没给这个字段赋值,就自动填默认值。

把这些约束组合起来,一张规范的用户表就出来了:

CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    age INT DEFAULT 18,
    city VARCHAR(50) DEFAULT '未知',
    is_member TINYINT(1) DEFAULT 0,
    created_at DATETIME DEFAULT NOW()
);

插入一条数据试试,只给必填的字段赋值,其他交给默认值和自增:

INSERT INTO user (username) VALUES ('小明');

SELECT * FROM user;

执行结果如下(created_at 实际以你插入时的时间为准):

idusernameagecityis_membercreated_at
1小明18未知02026-07-20 10:30:00

可以看到 id 自动是 1,age 自动是 18,created_at 自动是当前时间。如果再插入一次 username 为「小明」的记录,会直接报错,这就是 UNIQUE 约束在起作用。

如果上面的执行报「表已存在」,说明前面文章已经建过同名的 user 表,可以先执行 DROP TABLE IF EXISTS user; 再重新创建。

⚡ 改表结构:ALTER TABLE

表建好之后想加一列、删一列怎么办?不用删表重建,用 ALTER TABLE 就行:

ALTER TABLE user ADD email VARCHAR(100);

ALTER TABLE user DROP COLUMN email;

这两条分别是给 user 表加一个 email 列、再把它删掉。改表结构还有很多玩法,初学阶段知道有这回事、会加列删列就够用了。


💡 常见场景选型速查

场景推荐类型说明
用户 IDINT AUTO_INCREMENT主键自增,不用手动维护
用户名VARCHAR(50)长度不一,加 UNIQUE 防重复
手机号CHAR(11)长度固定,定长存储
余额DECIMAL(10, 2)金额必须精确,不能用 FLOAT
文章内容TEXT长文本,不参与条件查询
是否会员TINYINT(1)1 是真,0 是假
注册时间DATETIME业务时间,范围大不受限

🧾 小节总结

  • 整数用 INT;金额等精确小数用 DECIMALFLOAT 有浮点精度误差,和 JS 里 0.1 + 0.2 的问题同源。
  • 字符串:定长用 CHAR(手机号),变长用 VARCHAR(用户名),长文本用 TEXT
  • 日期时间:只用日期选 DATE,业务时间常用 DATETIMETIMESTAMP 跟随时区且只到 2038 年。
  • 布尔值用 TINYINT(1)1 为真、0 为假。
  • 约束是写入时的自动校验:PRIMARY KEYAUTO_INCREMENTNOT NULLUNIQUEDEFAULT 常组合使用。
  • 表结构可以用 ALTER TABLE 随时加列、删列,不必删表重建。

❓ 知识问答

Q1:金额为什么不能用 FLOAT?

FLOAT 是二进制浮点存储,会有精度误差,就像 JS 里 0.1 + 0.2 不等于 0.3 一样。金额差一分钱都可能引发对账问题,所以要用精确存储的 DECIMAL。

Q2:VARCHAR(50) 的 50 是字节还是字符?

在 MySQL 8.x 默认的 utf8mb4 字符集下是 50 个字符,中英文都按一个字符算,不用担心中文占多字节的问题。

Q3:手机号是数字,为什么不用 INT 存?

手机号可能以 0 开头,也不需要做加减运算,而且 11 位数字加区号可能超出 INT 范围。凡是「不参与计算的数字串」,比如手机号、身份证号,都应该用字符串存。

Q4:主键必须是自增数字吗?

不必须,主键的核心要求是「唯一且不为空」。实际项目里也有用 UUID 或雪花 ID 做主键的,但初学阶段自增 INT 简单直观,是常见选择。

Q5:NOT NULL 和 DEFAULT 必须一起用吗?

不是,但经常配合。NOT NULL 要求必须填,DEFAULT 负责「没填时自动补一个值」。两者一起用,插入数据时就能少写很多字段。


🧪 小练习

练习 1:设计一张 product 商品表,包含:自增主键 id、商品名 name(变长字符串,必填且唯一)、价格 price(精确到分)、库存 stock(整数,默认 0)、上架时间 created_at(默认当前时间)。写出完整建表语句。

-- 请在这里编写 SQL

练习 2:给上一题的 product 表加一个 category 分类列(VARCHAR(50)),然后插入两条商品数据(价格分别带小数),最后查询整张表验证结果。

-- 请在这里编写 SQL

🎉 恭喜你已经掌握 MySQL 常用数据类型与约束啦!下一篇我们学习多表关联查询,看看如何用 JOIN 把用户表和文章表连起来一起查。