MySQL 字段定义时的属性设置

开发的时候第一步就是建表,在创建表的时候,我们需要定义表的字段,每个字段都有一些属性,比如说是否为空,是否允许有默认值,是不是逐渐等。

这些约束字段的属性,可以让字段的值更符合我们的预期,也会为以后的数据查询和更新提供便利。

比如说,我们在定义字段的时候添加了默认值,那在插入数据的时候,如果我们没有主动指定这个字段的值(比如 Java 程序中),数据库就会使用默认值帮我们自动填充。

像在技术派项目中的文章详情表,我们为 id 字段设置了 NOT NULL、AUTO_INCREMENT、COMMENT 等属性。

那接下来,就来一起看看 MySQL 字段的常用属性都有哪些吧。

默认值

默认值(DEFAULT)是指在插入数据的时候,如果没有指定这个字段的值,那就会使用默认值。

我们创建这样一张表,包含了 varchar、int、datetime 等字段类型,每个字段都设置了默认值。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT '张三',`age` int(11) DEFAULT 18,`create_time` datetime DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在插入数据的时候,如果没有指定 name、age、create_time 字段的值,那就会使用默认值。

INSERT INTO `user` (`id`) VALUES (1);

可以看到,插入数据的时候,我们只指定了 id 字段的值,其他字段都省略了,但 MySQL 自动帮我们填充了默认值。

  1. DEFAULT '张三':指定了 name 字段的默认值为“张三”。
  2. DEFAULT 18:指定了 age 字段的默认值为 18。
  3. DEFAULT CURRENT_TIMESTAMP:指定了 create_time 字段的默认值为当前时间。

那假如我们没有指定默认值,又没有主动插入数据,那这个字段的值会是什么呢?

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255),`age` int(11),`create_time` datetime,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在插入数据的时候,我们没有指定 name、age、create_time 字段的值,也没有设置默认值。

INSERT INTO `user` (`id`) VALUES (1);

可以看到,此时,MySQL 帮我们填充的值是 NULL。

这就是为什么阿里巴巴开发规约要求我们,在POJO中,要使用包装类型,而不是基本数据类型,因为数据库的查询结构可能是 null,如果使用基本数据类型的画,因为要自动拆箱,会抛出NPE异常。

当然了,DEFAULT 也不能乱用,要根据业务需求来设置默认值,比如说,我们在创建用户表的时候,就不应该为 name 字段设置默认值,因为这样的话,如果用户没有填写名字,MySQL 就会默认填充“张三”,这显然是不合理的。

我们要尽早提示用户填写名字,而不是用默认值填充。

但对于 create_time 字段,我们就可以设置默认值为 CURRENT_TIMESTAMP,这样的话,MySQL 就会自动帮我们填充当前时间,Java 程序就不需要在插入数据的时候,手动填充时间了。

是否允许为空

有时候,我们会希望某个字段的值不能为空,比如说,用户名、手机号、邮箱等,这些字段的值都是必填的。

那我们在创建表的时候,就会明确指定这些字段是 NOT NULL 的。

这样在插入数据的时候,如果我们没有指定 name、mobile、email 字段的值,那 MySQL 就会报错。

虽然我们也会在 Java 程序中对这些字段进行校验,但在数据库层面,也要对字段的值进行约束,这样可以更好地保证数据的完整性。

主键

主键(PRIMARY KEY)是用来唯一标识一条记录的,一个表中只能有一个主键,主键的值不能重复,也不能为 NULL。

主键的指定方式有两种,一种是在字段定义的时候直接跟上 PRIMARY KEY,另一种是在所有字段定义完成后,再通过 PRIMARY KEY(字段)这种方式指定。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,`name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

或者

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

第二种方式在复合主键(由两个或更多的字段组合而成)的时候会更加方便,比如说,我们要为学生课程表设置复合主键,就可以这样定义。

CREATE TABLE `student_course` (`student_id` int(11) NOT NULL,`course_id` int(11) NOT NULL,created_time datetime DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`student_id`, `course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

通过 PRIMARY KEY 关键字后面跟上括号内的多个字段名来实现。

不过,复合主键会创建更复杂的索引,可能会对插入、更新、删除等操作的性能产生影响,另外,在执行联合查询

的时候,因为需要处理复合主键的多个字段,也会使 SQL 查询语句变得复杂。

所以在实际开发中,复合主键的使用频率并不高。

自增

自增(AUTO_INCREMENT)是指在插入数据的时候,如果没有指定这个字段的值,那 MySQL 就会自动帮我们填充一个递增的值。

一般用于类型为整型的主键字段,比如说 int 或 bigint。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我们来插入几条数据,看看 id 字段的值是怎么填充的。

INSERT INTO `user` (`name`) VALUES ('张三');
INSERT INTO `user` (`name`) VALUES ('张四');
INSERT INTO `user` (`name`) VALUES ('张五');

再删除一条数据后插入:

DELETE FROM `user` WHERE `id` = 2;
INSERT INTO `user` (`name`) VALUES ('张六');

可以看到,每次插入数据的时候,id 都会在以前的最大值上加 1。

注释

注释(COMMENT)是指在字段定义的时候,可以添加一些描述性的文字,和 Java 中中的双斜杠注释类似。

语法也非常简单,就是在字段定义的后面跟上 COMMENT '注释内容'(建议单引号)。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL COMMENT '姓名',`age` int(11) NOT NULL COMMENT '年龄',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这样的话,我们在查看表结构的时候,就可以看到每个字段的注释了。

SHOW FULL COLUMNS FROM `user`;

注释的作用是让其他人更容易理解这个字段的含义,没啥好说的。

UNIQUE

UNIQUE可以确保一列或几列的组合值在整张表中是唯一的。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`mobile` varchar(11) UNIQUE,`email` varchar(255),PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这样的话,我们在插入数据的时候,如果 mobile 的值已经存在,MySQL 就会报错。

INSERT INTO `user` (`name`, `mobile`, `email`) VALUES ('张三', '12345678901', '982323232@qq.com');
INSERT INTO `user` (`name`, `mobile`, `email`) VALUES ('张四', '12345678901', 'www.huahua@169.com');

等于说在数据库层面就对字段的值进行了唯一性约束,虽然如果一个字段不允许重复的话,在 Java 程序中也会先进行校验。

当然,也可以对过个字段进行唯一性约束,语法和复合主键类似,用 UNIQUE 关键字后面跟上括号内的多个字段名来实现。比如说,我们要为学生课程表设置复合唯一性约束,就可以这样定义。

CREATE TABLE `student_course` (`student_id` int(11) NOT NULL,`course_id` int(11) NOT NULL,created_time datetime DEFAULT CURRENT_TIMESTAMP,UNIQUE (`student_id`, `course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

也可以为 UNIQUE 约束指定别名,比如说,我们 mobile 字段设置唯一性约束,就可以这样定义。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`mobile` varchar(11),`email` varchar(255),PRIMARY KEY (`id`),UNIQUE `mobile_unique` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

UNIQUE 约束既可以保证数据的唯一性,也可以提高数据检索的效率,因为它会为对应的列创建一个唯一索引。

可以通过 SHOW INDEX FROM 表名 来查看索引信息。查看 Non_unique 列的值,可以确认是否为唯一索引(0 表示唯一,1 表示非唯一)

SHOW INDEX FROM `user` \G

的确,我们可以看到 mobile 字段的 Non_unique 是 0,也就是唯一索引,索引类型是 BTREE,这是一种高效的索引结构。

不过,与 PRIMARY KEY 不同,UNIQUE 约束允许有 NULL 值。我们来测试一下:

INSERT INTO `user` (`name`,`email`) VALUES ('张三', '234536076@qq.com');
INSERT INTO `user` (`name`,`email`) VALUES ('张三', '234536076@qq.com');

我们来看一下结果,果然允许 NULL 值。

既然 UNIQUE 约束是用来保证数据的唯一性的,为什么允许有多个 NULL 值呢?

主要与 NULL 值在 SQL 中的特殊含义有关。在 SQL 中,NULL 代表一个未知值或不存在的值。当我们对数据库设计时使用 UNIQUE 约束时,这个约束确保了所有的非 NULL 值在该列中是唯一的,但是对于 NULL 值的处理则有所不同,因为 NULL 与任何其他值(包括另一个 NULL)都不相等。

在技术派中的文章详情表,我们为 article_id 和 version 字段设置了唯一性约束,这样的话,就可以保证每篇文章的每个版本都是唯一的。

外键

外键(FOREIGN KEY)是用来建立两个表之间的关联关系的,它指向另一张表的主键。

下面是一个简单的例子,我们创建了两张表,一张是用户表,一张是订单表,用户表的 id 字段是主键,订单表的 user_id 字段是外键,指向用户表的 id 字段。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`mobile` varchar(11) UNIQUE,`email` varchar(255),PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `order1` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULL,`order_no` varchar(255) NOT NULL,PRIMARY KEY (`id`),FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我们先在 user 中插入一条数据:

 insert into `user` (`name` , `mobile` ,`email`) values ("张三" , "19203004404" ,"1213232@qq.com");

这样的话,我们在插入订单的时候,如果 user_id 指向的用户不存在,MySQL 就会报错。

INSERT INTO `order1` (`user_id`, `order_no`) VALUES (1, '2024020801');
INSERT INTO `order1` (`user_id`, `order_no`) VALUES (2, '2024020802');

可以看到,user_id 为 2 的订单插入失败了,因为 user_id 为 2 的用户不存在。

Cannot add or update a child row: a foreign key constraint fails (itwanger.order, CONSTRAINT order_ibfk_1 FOREIGN KEY (user_id) REFERENCES user (id))

外键约束可以确保数据的完整性,比如说,我们在删除用户的时候,如果用户有订单,就不允许删除。

DELETE FROM `user` WHERE `id` = 1;

外键是 MySQL 中不可或缺的一部分,它通过确保表之间的数据引用完整性,帮助构建结构化和组织良好的数据库模式。正确使用外键不仅可以保证数据的一致性和准确性,还可以提高数据库操作的效率。

ZEROFILL

ZEROFILL 是指在插入数据的时候,如果字段的值小于字段的长度,MySQL 就会在字段的值前面填充 0。

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`money` int(11) ZEROFILL,`father_money` int(11),PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我们来插入一条数据,看看 id 字段的值是怎么填充的。

INSERT INTO `user` (`money`, `father_money`) VALUES (1, 1);

可以看到,money 字段的值是 00000000001,而 father_money 字段的值是 1。

当一个字段被定义为 ZEROFILL 时,MySQL 会自动为该字段的值填充前导零,直到达到该字段定义的宽度。这个属性常常与数值类型的字段一起使用,以确保显示的数值具有固定的宽度,这对于报表和数据展示的格式化非常有用。

特别注意:

  1. ZEROFILL 属性仅影响数值的显示方式,并不改变存储在数据库中的实际值。例如,无论是否使用 ZEROFILL,数值 123 都存储为 123,只是显示时可能会不同。
  2. ZEROFILL 填充的零只是为了达到字段定义的显示宽度,它并不影响字段的存储范围或存储大小。
  3. 当字段被定义为 ZEROFILL 时,MySQL 也会自动将其标记为 UNSIGNED。这是因为前导零填充通常只对正数有意义。

OK,我们通过 show columns from user like 'money'; 来查看一下字段的属性。

可以看到,money 字段的属性中,有 ZEROFILL 和 UNSIGNED。

除了通过这种方式,也可以通过 desc table_name 来查看表的结构。

总结

字段的属性设置是 MySQL 表设计中的重要一环,掌握它们是非常有必要的。这次我们依次讲了默认值、是否允许为空、主键、自增、注释、唯一性约束、外键、ZEROFILL 等属性。

这里温馨提示一点,尽量不要使用 MySQL 的关键字,尽管我们可以通过反引号(`)来避免关键字冲突,但这样会使 SQL 语句变得复杂,不利于维护。

尤其是一些关键字和 Java 当中的关键字重合时,很容易出现意料之外的错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/762222.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HCIP—BGP路由聚合

在大型网络中,路由条目通常多达成千上万条,甚至几十万条,这给路由设备带来的挑战是:如何存储并有效管理如此众多的路由信息? BGP是一种无类路由协议,支持CIDR、VLSM和路由聚合。路由聚合技术的使用…

[Linux开发工具]——gcc/g++的使用

Linux编译器——gcc/g的使用 一、快速认识gcc/g二、程序的翻译过程2.1 预处理(.i文件)2.2 编译(.s文件)2.3 汇编(.o文件)2.4 链接(生成可执行文件或库文件) 三、认识函数库3.1 静态库…

微调alpaca-lora遇到的一些问题

1、环境简介 环境: 系统:Ubuntu torch:2.2.1 python:3.10 gpu:V100 16g peft:0.9.0 使用PEFT中的lora方式微调llama-2-7b-hf,项目地址:alpaca-lora 2、混合精度训练Tensor相互计算会…

Jupyter Notebook介绍、安装及使用教程

Jupyter Notebook介绍、安装及使用教程 一、什么是Jupyter Notebook?简介组成部分网页应用文档Jupyter Notebook的主要特点 二、安装Jupyter Notebook先试用,再决定安装安装前提使用Anaconda安装使用pip命令安装 三、运行Jupyter Notebook帮助启动默认端…

macOS 通过 MacPorts 正确安装 MySQL 同时解决无法连接问题

如果你通过 sudo port install 命令正常安装了 MySQL,再通过 sudo port load 命令启动了 MySQL Server,此刻却发现使用 Navicat 之类的 GUI 软件无法连接,始终返回无法连接到 127.0.0.1 服务器。这是一个小坑,因为他默认使用了 So…

零代码编程:用kimichat将srt字幕文件进行批量转换合并

文件夹里面有多个srt字幕文件,借助kimichat可以很方便的对其进行批量合并。 在kimichat中输入提示词: 你是一个Python编程专家,写一个Python脚本,完成一个处理整理文档内容的任务,具体步骤如下: 打开文件…

更新数据库表中的数据

目录 update 加上各种限制条件 update update 表名set 列名1xx,列名2xx 指定更新某列数据如果不添加where子句,则为全列更新 也可以在原有基础上更新: 注意,mysql语法里不支持,必须是列名列名数值 加上各种限制条件 比如加上order by子句,where子句,limit等 这些条件对于up…

【FLOOD FILL专题】【蓝桥杯备考训练】:扫雷、动态网格、走迷宫、画图、山峰和山谷【已更新完成】

目录 1、扫雷(Google Kickstart2014 Round C Problem A) 2、动态网格(Google Kickstart2015 Round D Problem A) 3、走迷宫(模板) 4、画图(第六次CCF计算机软件能力认证) 5、山…

政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(四)—— 过拟合和欠拟合

政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正! 通过增加容量或提前停止来提高性能。 在深度学习中&#…

C#对于文件中的文件名判断问题

C#中对于文件名的判断问题,我们使用bool值进行值的传递,首先我们使用内置方法进行文件字符串匹配的bool值回传,我们打印出文件名以及相对应的bool,即可知道文件名是否真正生效 bool isHave fileName.Contains("Hello"…

代码学习记录22--回溯算法第三天

随想录日记part22 t i m e : time: time: 2024.03.17 主要内容:今天主要是结合类型的题目加深对回溯算法的理解:1.组合总和;2.组合总和 ;3.分割回文串。 39. 组合总和 40.组合总和II131.分割回文串 Topic1组合总和 题…

【Node.js从基础到高级运用】十四、Node.js 错误处理与日志记录

引言 在这篇博客文章中,我们将深入探讨Node.js中的错误处理和日志记录的最佳实践。我们会了解如何在Node.js应用程序中有效地捕获和处理错误,并利用日志库如morgan来记录应用程序的活动和错误信息。 第1部分:Node.js中的错误处理 同步代码中…

Spring AI Embeddings 和 Vector 入门

在前面 Spring AI Chat 简单示例 中介绍了 Chat 的基本用法,本文在此基础(主要是pom.xml)上继续探索 Embedding 和 Vector。 官方文档: embeddings: https://docs.spring.io/spring-ai/reference/api/embeddings/openai-embedding…

断点重训教程:如何有效地保护深度学习模型训练进度

在深度学习领域,长时间训练是常见的需求,然而,在训练过程中可能会面临各种意外情况,比如计算机故障、断电等,这些意外情况可能导致训练过程中断,造成已经投入的时间和资源的浪费。为了应对这种情况&#xf…

Avue框架实现图表的基本知识 | 附Demo(全)

目录 前言1. 柱状图2. 折线图3. 饼图4. 刻度盘6. 仪表盘7. 象形图8. 彩蛋8.1 饼图8.2 柱状图8.3 折线图8.4 温度仪表盘8.5 进度条 前言 以下Demo,作为初学者来说,会相应给出一些代码注释,可相应选择你所想要的款式 对于以下Demo&#xff0c…

GStreamer简单看看

主要是现在弄摄像头,要用到这东西。所以学学。 最权威主页:GStreamer: open source multimedia framework 大概看了下,好像命令也不难。 gst-launch-1.0 v4l2src device/dev/video0 ! video/x-raw,formatYUY2,width640,height480,framerat…

说说你对webpack的理解?解决了什么问题?

文章目录 一、背景二、问题三、是什么参考文献 一、背景 Webpack 最初的目标是实现前端项目的模块化,旨在更高效地管理和维护项目中的每一个资源 模块化 最早的时候,我们会通过文件划分的形式实现模块化,也就是将每个功能及其相关状态数据各…

Batch Normalization(批量归一化)和 Layer Normalization(层归一化)

Batch Normalization(批量归一化)和 Layer Normalization(层归一化)都是深度学习中用于改善网络训练过程的归一化技术。尽管它们的目标相似,即通过规范化中间层的激活值来加速训练过程并提高性能,但它们在细节上有所不同。 Batch Normalization (批量归一化) Batch Nor…

谷歌地图TMS地图服务地址收集2024,测试可用

对于普通的开发者或者GIS从业者来说,免费的底图影像服务,太重要了。之前写过一篇谷歌地图的TMS地址收集的博文,由于谷歌网站关闭已经不能用。最近又发现了谷歌在国内开放了其他地址,在这里给大家分享一下。 https://gac-geo.googl…

Ant Design Vue和VUE3下的upload组件使用以及文件预览

Ant Design Vue和VUE3下的upload组件使用以及文件预览 文章目录 Ant Design Vue和VUE3下的upload组件使用以及文件预览一、多文件上传1.需求2.样例3.代码 二、单文件上传1. 需求2. 样例3.代码 二、多文件上传产生的时间超时问题三、文件系统名称更改1. 修改文件index.html2. 修…