MySQL的数据类型和约束

文章目录

数据类型

一、整数类型

类型 字节 有符号范围 无符号范围 常见场景
tinyint 1字节 -128 ~ 127 0 ~ 2 8 − 1 2^{8} - 1 28−1 状态、枚举小范围
smallint 2字节 − 2 15 -2^{15} −215 ~ 2 15 − 1 2^{15} - 1 215−1 0 ~ 2 16 − 1 2^{16} - 1 216−1 小范围数量、等级
mediumint 3字节 − 2 23 -2^{23} −223 ~ 2 23 − 1 2^{23} - 1 223−1 0 ~ 2 24 − 1 2^{24}-1 224−1 少见
int 4字节 -21亿 ~ 21亿 0 ~ 42亿 常规的id、计数
bigint 8字节 超级大 超级大 用户id、订单id

tinyint最常见的

sql 复制代码
status tinyint unsigned not null default 0 comment '状态:0正常,1禁用,2删除';

适合:

  • 用户状态
  • 订单状态
  • 性别
  • 是否删除
  • 小范围枚举

bigint适合用户量极大,点击量极大的场景,数据量增长大,int很容易不够用,一次性开够

适合:

  • 用户id
  • 订单id
  • 支付流水id
  • 消息id
sql 复制代码
user_id bigint unsigned not null comment '用户id'
order_id bigint unsigned not null comment '订单id'

二、浮点类型和定点类型

值得注意的是:无符号类型的浮点和定点类型,直接砍掉负数部分,范围是0 ~ XX.XX

float(m,d)

  • m:总位数
  • d:小数位数

比如说:float(5,2),总共五位数,小数点占两位,最大到999.99

需要注意:float是浮点数,存在精度误差

double

doublefloat精度高,占8字节,但是依旧是浮点数,存在精度误差

适合:

  • 科学计算
  • 统计估算
  • 经纬度

decimal

decimal可以规避精度损失

涉及到金融、电商、支付、金钱的业务,务必用decimal,要保证一分都不能出错

sql 复制代码
amout decimal(10, 2) not null default 0.00 comment '金额'
  • 总共10位
  • 小数精确到2位
  • 整数最多8位
  • 最大值约为99999999.99

常见的有:

sql 复制代码
price decimal(10,2) not null default 0.00 comment '商品价格'
balance decimal(18,2) not null default 0.00 comment '账户余额'
rate decimal(5,4) not null default 0.0000 comment '费率'

三、字符串类型

char(n)

固定长度字符串,给多少就开多少空间

例如:

sql 复制代码
gender char(1) not null comment '性别:m男,f女'

适合:

  • 固定长度的编码
  • 性别
  • 手机区号

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个字符

适合:

  • 用户名
  • 昵称
  • 邮箱
  • 标题
  • 地址
  • URL

例如:

sql 复制代码
username varchar(64) not null comment '用户名'
email varchar(128) default null comment '邮箱'
nickname varchar(64) not null default '' comment '昵称'
title varchar(255) not null comment '标题'

text大文本

见类型:

类型 最大长度 场景
tinytext 255 字节 很短文本
text 64KB 文章内容、描述
mediumtext 16MB 长文章
longtext 4GB 超长文本,很少直接用

例如:

sql 复制代码
content text comment '文章内容'
description text comment '商品描述'

需要注意:大字段尽量不要和高频查询字段放在同一张表中

  • 大字段会影响缓存命中
  • 这样可以减少IO,提高效率

四、日期时间类型

date

sql 复制代码
birthday data default null comment '生日'

适合:

  • 生日
  • 日期
  • 统计日期
  • 入职日期

格式:YYYY-MM-DD,占用3字节

time

sql 复制代码
duration time comment '时长'

格式:HH:MM:SS

适合:

  • 时间间隔
  • 当天时间点
  • 持续时间

耗时使用整数秒/毫秒:

sql 复制代码
duration_ms int unsigned not null default 0 comment '耗时毫秒'

datetime

占用8字节,适合:

  • 创建时间
  • 更新时间
  • 业务发生时间
  • 订单时间

范围很大:1000-01-01 ~ 9999-12-31

不受时区转换影响,这个底层逻辑是,把这个时间刻在硬盘上,硬盘带到哪个时区,读出来的时间永远不变

timestamp

本质是一个时间戳,不存年月日,存的是一个整数 ,从 1970 年 1 月 1 日 0 点 0 分 0 秒(UTC 零时区)到现在,一共过了多少秒

会随主机的时区变化:

  • 存入:MySQL会先看当前系统处于什么时区,把传进来的时间换算成时间戳,存入硬盘
  • 读取:MySQL把硬盘那串时间戳秒数逃出来,再根据查询的客户端所在时区,换算成当地时间展示

timestamp只能存到2038年

timestamp底层是一个4字节的带符号整数,最大值 2 31 − 1 = 2147483647 2^{31} - 1 = 2147483647 231−1=2147483647,时间到了2038年1月19日凌晨 03:14:07 时,从1970年开始算的秒数刚好是 2147483647 2147483647 2147483647,再往后走一秒,溢出了

五、enumset

enum枚举,多选一

sql 复制代码
gender enum('male', 'female', 'unknown') not null default 'unknown'

内部是索引:

text 复制代码
male -> 1
female -> 2
unknown -> 3

可以这样查询:

sql 复制代码
select * from user where gender = 'male'

查看某个枚举值:

sql 复制代码
select * from user where gender = 'male'

查询某个字段是否等于几个枚举值:

sql 复制代码
select * from user where gender in ('male', 'unknown')

enum存在以下问题:

  • 新增枚举值就需要改变表结构
  • 跨语言、跨服务维护成本高

set不定项选择,类似位图

sql 复制代码
hobby set('music', 'sport', 'game', 'read')

底层类似位图,查询可以:

sql 复制代码
select * from user where find_in_set('music', hobby)
# 或者是
select * from user where hobby & 1

约束

非空约束

not null 约束用户必须插入一个值

sql 复制代码
username varchar(64) not null commnet '用户名'
status tinyint unsigned not null default 0 comment '状态'
created_at datetime not null default current_timestamp commnet '创建时间'

null不参与运算,代表没有,而不是空值,空值是

缺省值

default的使用:

  • 当用户忽略这一列时,用这个缺省值
  • 没有缺省值且约束了not null,忽略这一列会报错

使用中,建议:

数字:

sql 复制代码
conut int unsigned not null default 0

字符串:

sql 复制代码
nickname varchar(64) not null default ''

状态:

sql 复制代码
status tinyint unsigned not null default 0

时间:

sql 复制代码
created_at datetime not null default current_timestamp

注释

comment是写给程序员的,协作开发一定要写注释

主键约束

一张表最多一个主键,但是主键可以由多列组成,变成复合主键

单列主键

sql 复制代码
id bigint unsigned not null primary key comment '主键id'

要求:

  • 唯一
  • 非空
  • 不要频繁修改

主键为什么通常使用整数?

  • 整数比字符串省空间
  • 整数查找比字符串块
  • 自增主键插入顺序友好

自增主键

sql 复制代码
id bigint unsigned not null auto_increment primary key

auto_increment对应的字段不给值,会自动被系统触发,系统会从当前字段中已经有的最大值+1,得到一个新的不同的值,搭配主键使用

特点:

  • 自增长字段是整数
  • 一张表最多只能有一个自增长
  • 任何字段做自增长,必须是一个索引

复合主键

多种列属性是强绑定的,比如课程名称和课程号是一一对应的,那么就可以设置成复合主键

以下的案例是,一个学生不能重复选一门课程

sql 复制代码
create table student_course(
	student_id bigint unsigned not null,
    course_id bigint unsigned not null,
    score int default null,
    primary key (student_id, course_id)
)

唯一键

主键标识行唯一,唯一键保证业务字段不重复

比如说有个手机号,身份证号,这些都得保证每个人的属性都是不同的,不能重复

sql 复制代码
phone varchar(20) not null unique comment '手机号'

唯一键可以有多个null,因为null不参与运算,不计数

外键

保证两张表之间的数据关系不能乱

举个例子:用户表和订单表

一个用户可以有多个订单,所以用户表是父表,订单表是子表

用户users

sql 复制代码
create table users (
	id bigint primary key,
    name varchar(64)
);

订单表orders:

sql 复制代码
create table orders(
	id bigint primary key,
    user_id bigint,
    amount decimal(10,2),
    foreign key (user_id) references users(id)
);

foreign key (user_id) references users(id)这一行规定了,order.user_id的值必须在users.id里面存在

插入两个真实用户:

sql 复制代码
mysql> insert into users values(1, 'kunkun');
Query OK, 1 row affected (0.10 sec)

mysql> insert into users values(2, 'lele');
Query OK, 1 row affected (0.01 sec)

插入合法订单:

sql 复制代码
mysql> insert into orders values (101, 1, 99.50);
Query OK, 1 row affected (0.03 sec)

mysql> insert into orders values (102, 2, 110);
Query OK, 1 row affected (0.02 sec)

插入不存在的用户,会报错:

sql 复制代码
mysql> insert into orders values (12, 3, 120);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails 

子表orders想插入user_id = 3,但是父表中users不存在这个id,拦截

外键不允许子表引用不存在的父表数据

修改订单归属,会报错:

sql 复制代码
mysql> update orders set user_id = 888 where id = 101;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails

外键不允许子表把引用改成不存在的父表数据

删除被引用的用户,会报错

sql 复制代码
mysql> delete from users where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails

外键不允许父表删除仍被子表引用的数据->得先把数据删干净

总结一下外键的作用:

子表里引用父表的值,必须真实存在,不能乱改,不能断关系

done~

相关推荐
八秒记忆的老男孩2 小时前
Sentinel5P的L1B级数据预处理(BD7和BD8)【20260427】
数据库·redis·缓存
ChoSeitaku2 小时前
5.MySQL表的约束|空属性|默认值|列描述|主键|自增长|唯一键|外键
android·数据库·mysql
S1998_1997111609•X2 小时前
滄集/㞯鎩.赫量被恶意篡改?|\^*仺\~:sall,sql=㶏齾bci.ji.app_sql=-heart{TCP.box}‘雧……㞋
网络·数据库·网络协议·百度·微信
2301_803875612 小时前
c++如何通过重定向streambuf流捕获标准错误输出并记录到运行日志【详解】
jvm·数据库·python
2301_795099742 小时前
HTML怎么创建时间轴布局_HTML结构化时间线写法【方法】
jvm·数据库·python
运气好好的2 小时前
CSS组件库如何快速扩展_通过Sass @extend继承基础布局
jvm·数据库·python
m0_613856292 小时前
Go install 命令失效原因解析与正确使用指南
jvm·数据库·python
A_aspectJ2 小时前
【Java基础开发】基于 Java Swing +MySQL + JDBC 版实现图书管理系统
java·开发语言·mysql
星马梦缘2 小时前
数据库作战记录6 实验6
数据库·oracle