文章目录
1. 数据类型
理解数据类型的意义
MySQL的数据类型是告诉数据库:
这个字段存什么样的数据、占多少空间、能做什么运算、怎么比较和排序
所有的数据类型都是根据对象模型的字段属性决定的
类比C++,大概有这些类型:
| C++ | MySQL | 作用 |
|---|---|---|
int | int | 普通整数 |
long long | bigint | 大整数 |
string | varchar / text | 字符串 |
bool | boolean / tinyint(1) | 布尔值 |
double | double | 浮点数 |
| 精确金额类型 | decimal | 金额、余额 |
| 时间对象 | datetime | 日期时间 |
区别是:
- C++ 类型主要服务于内存计算
- MySQL 类型服务于长期存储、查询、比较、排序、约束
常见数据类型
int
用于普通整数,4字节
比如:
age int
stock int
status int
适合数据量适中的场景:
- 年龄
- 库存
- 数量
- 状态码
- 次数
bigint
用于大整数,8字节
主键ID经常用:
id bigint primary key auto_increment
对于大规模业务、订单、消息、日志、AI调用记录可能增长极快,bigint范围大,更安全,一次性开够空间
比如:
user_id bigint
order_id bigint
message_id bigint
tinyint
用于小整数,1字节
status tinyint unsigned not null default 0 comment '状态:0正常,1禁用,2删除';
适合:
- 用户状态
- 订单状态
- 性别
- 是否删除
- 小范围枚举
varchar(n)
用于短字符串,括号里的是字符数上限,实际用多少占用多少空间
n是字符数,而不是字节数,底层会根据当前的字符集算出实际占用多少字节:
utf8占用3字节utf8mb4占用4字节,支持emoji
varchar可以指定0~65535之间的值,但是有1 - 3字节用于记录数据大小,所以有效字节数是65532
编码是utf8时,n的最大值是
65532
÷
3
=
21844
65532 \div 3 = 21844
65532÷3=21844,所以最多只能存21844个字符
特点:
- 变长存储
- 适合长度有限的文本
- 可以设置最大长度
text
用于长文本
比如AI聊天内容、文章正文
适合:
- 文章正文
- 评论内容
- AI恢复内容
- 用户长输入
- 提示词
例如:
CREATE TABLE messages (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
content TEXT NOT NULL
);
datetime
用于日期时间
常见字段有:
created_at DATETIME NOT NULL # 创建时间
updated_at DATETIME NOT NULL # 更新时间
paid_at DATETIME # 支付时间
deleted_at DATETIME # 删除时间
不受时区转换影响,这个底层逻辑是,把这个时间刻在硬盘上,硬盘带到哪个时区,读出来的时间永远不变
decimal(m,n)
decimal可以规避精度损失
涉及到金融、电商、支付、金钱、token计费的业务,务必用decimal,要保证一分都不能出错
例如:
price DECIMAL(10,2) NOT NULL
balance DECIMAL(10,2) NOT NULL
DECIMAL(10,2) 的意思是:总共最多 10 位数字,其中小数点后 2 位
值得注意的是:非负浮点类型直接砍掉负数部分,从0开始
比如:unsigned float(3,2),范围是:[0,9.99]
2. 表的约束
理解约束的意义
约束是让数据库帮用户守住数据正确性的底线
如果没有约束,错误数据很容易进入数据库,这个约束是数据库的兜底操作
常见约束
主键约束 primary key
主键用于唯一标识一行数据
特点:
- 不能重复
- 不能为空
- 一张表一个主键
- 后端经常通过主键查询、修改、删除
为什么后端喜欢用
id来做主键?
- 稳定,业务字段可能变化,
id基本不变,就像身份证一样- 短小,主键常出现在查询条件、关联字段、索引中,整数比较和存储都会比字符串高效
例如:
id bigint primary key auto_increment
主键就是后端定位数据的核心
假设这个id是用户表的主键id,那么就表名:
- 每个用户都有自己一个唯一的
id id不能重复id不能为空- 后端可以通过这个
id精确定位这个用户
自增 auto_increment
自增标识插入数据时,MySQL自动生成递增的id
例如:
id bigint primary key auto_increment
插入时不需要写id:
insert into users (username, email)
values ('tom', 'tom@163.com');
MySQL会自动分配ID
注意:自增不是约束本身,只是常和主键一起使用
非空约束 not null
表示这个字段不能为空
适合加not null的字段:
- 用户名
- 密码哈希
- 商品名称
- 商品价格
- 库存
- 创建时间
- 消息内容
…
唯一键约束 unique
表示字段值不能重复,是业务规则
例如:
email varchar(50) not nulll unique
表示一个邮箱只能注册一个账号
常见的有:
- 邮箱,邮箱登录不能重复
- 手机号,手机号注册不能重复
- 订单号,订单号都是唯一的
注意:唯一键约束不仅能保证数据正确,还能防止并发情况下重复写入
比如说:两个请求同时注册一个邮箱,如果靠后端代码先查再插入,会有并发冲突,加上数据库唯一约束,数据库会兜底拦住重复邮箱
主键和唯一键有什么区别?
- 一张表只能有一个主键,但是可以有多个唯一键
- 主键只有一个
id,唯一键可以有邮箱、手机号…- 主键不能为空,唯一键可以允许多个为空
- 可以插入多行
phone = null,这表示未知,多个未知值不被认为是相等的,NULL不参与运算- 主键表示身份唯一性,唯一键表示业务唯一性
综上:主键解决这一行数据是谁的问题,唯一键解决这个业务能不能重复的问题
默认值 default
如果插入时不传某字段的值,MySQL自动填默认值,就是C++中的缺省参数
例如:
status tinyint not null default 1
表示默认状态是1
外键约束 foreign key
基础认知
用一个表里的字段,引用另一个表的主键或者唯一键,从而表示表与表之间的关系
例如:
用户表:
create table users(
id bigint primary key auto_increment,
username varchar(50) not null
);
订单表:
create table orders(
id bigint primary key auto_increment,
user_id bigint not null,
total_amount decimal(10,2) not null,
foreign key (user_id) references users(id)
);
这里的foreign key (user_id) references users(id)表示:
orders.user_id必须引用user.id中已经存在的用户,不能给一个不存在的用户创建订单
如果不加外键,插入:
insert into orders (user_id, total_amount)
values (9999,12.6)
即使users表里没有id = 9999的用户,MySQL也不会拦截,此时就造成有订单,但是找不到对应用户
外键怎么用
建表要求
先建父表,再建子表
父表:users
create table users(
id bigint primary key auto_increment,
username varchar(50) not null
);
子表:orders
create table orders(
id bigint primary key auto_increment,
user_id bigint not null,
total_amount decimal(10,2) not null,
foreign key (user_id) references users(id)
);
user.id是被引用字段
插入顺序
有外键约束,必须先有父表数据,再插入子表数据
正确顺序:
insert into users (username)
values('vect');
insert into orders (user_id, total_amount)
values(1, 99.5);
删除顺序
有外键约束时,如果一个用户下面有订单,直接删除会失败
例如:
delete from users
where id = 1;
如果orders里还有user_id = 1,MySQL会拦截删除,因为删除了用户,订单成了孤儿数据
正确做法,先删除子表里的数据,再删除对应父表的数据
为啥不推荐使用外键?
- 外键会增加写入开销,有外键,多了一次约束检查,高并发场景下会带来负担
- 外键会引入额外锁和阻塞
- 外键检查可能涉及到父表和子表之间的锁,比如:
- 一个事务在删除用户
- 一个事务在插入该用户的顶顶那
- 一个事务在更新用户字段
- 上述操作会产生锁的竞争等待,甚至有死锁的风险
- 外键检查可能涉及到父表和子表之间的锁,比如:
- 外键让表的关系强耦合
- 分库分表后外键很难维护
- 用户表被分到多个库
- 订单表被分到多个库
- 此时外键基本失效,MySQL外键通常只能在同一个数据库实例、同一个存储引擎、兼容条件下工作,跨库、跨服务很难靠外键保证
好的做法是保留逻辑的外键,不适用数据库外键,而是在后端代码中实现外键约束
done~
2168

被折叠的 条评论
为什么被折叠?



