前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【MySQL】MySQL数据库的初阶使用

【MySQL】MySQL数据库的初阶使用

作者头像
举杯邀明月
发布2023-10-17 13:42:39
3380
发布2023-10-17 13:42:39
举报
文章被收录于专栏:C++&linux

一、MySQL服务的安装

1. 安装mysql服务器的时候,我们将用户身份切换为root,安装好之后普通用户也是可以通过MySQL命令行式的客户端来访问mysqld服务,初期学习MySQL的时候建议直接使用root的身份来进行学习,快速上手基本的sql语句编写之后,我们在后期学习用户管理时,可以自己手动新建普通用户,给普通用户赋予一定的数据库管理权限。

2. 安装MySQL需要分为两个步骤,首先需要卸载干净掉云服务器上可能预先内置的MySQL服务,我们需要将原有的环境先卸载干净,然后在服务器上重新安装布置MySQL服务。 (1)云服务器上可能内置了mariadb(MySQL的一个开源分支)或MySQL,所以先查看一下是否有这些服务,如果有则将这些服务停止掉。查看是否存在服务的指令: ps axj | grep mariadb 停止服务的指令:systemctl stop mariadb.service 停止掉服务之后,我们可以继续ps axj | grep mariadb 或 ps axj | grep mysql 查看系统中是否有这些存储服务,如果没有,说明我们停止成功。 (2)如果你曾经安装过mysql或mariadb服务,则系统中一定会留有yum源安装时,从远端拉取到本地的安装包,这些安装包的后缀都是rpm,查看所有的yum残留安装包的指令:rpm -qa,查看mariadb或mysql残留安装包的指令:rpm -qa | grep mysql 和 rpm -qa | grep mariadb,卸载时如果一个一个卸载可能有些麻烦,所以我们可以通过rpm查询后的结果通过管道传输,然后将管道传输的内容传递给xargs指令,xargs再将这些文件名传递给yum remove指令,让yum remove统一卸载这些残留的安装包,卸载的指令为:rpm -qa | grep mysql | xargs yum -y remove,卸载成功后,我们可以再次调用rpm -qa | grep mysql查看是否还有剩余的安装包,如果没有,则说明我们已经卸载残留的安装包成功了。 (3)当系统中已经停止掉了mysqld服务,并且卸载了所有的剩余安装包,则说明原有环境已经干净了。为了检验原有环境是否完全干净,我们还可以ls /etc/my.cnf查看是否存在my.cnf这个文件,如果该文件不存在,则环境已经干净了。ls /var/lib/mysql中的内容是上一个mysql数据库中所残留的数据,MySQL服务在卸载的时候,默认不会将数据删除掉,这些数据我们可以不用管,他们并不影响我们后续MySQL服务的安装和使用。

3. (4)接下来我们就可以正式的在我们linux机器上部署MySQL服务了,首先我们需要去官方下载官方的mysql yum源mysql yum源地址,打开地址后会有很多版本的mysql yum源,确保我们下载正确的mysql版本之前,我们需要查看一下自己linux机器的版本,cat /etc/redhat-release,点开网页之后其实是找不到centos 7.6版本的yum源的,我们需要右键查看页面源代码,显示出完整信息之后,就找el7的,el代表centos,至于MySQL服务的版本不需要选择太新的,选择MySQL5.7版本的即可,147行的yum源就正好符合我的linux机器版本以及我所需要的mysql服务版本。 下载之后我们可以将该文件ctrl+x剪切到桌面上(方便查找),然后在xshell下可以通过sudo rz命令将桌面上的yum源文件上传到linux机器上,注意xshell不支持从桌面拖拉文件到xshell界面的方式来上传文件,必须通过rz指令来上传文件到linux机器上。 上传之后我们就会得到一个以.rpm为后缀的yum源文件,然后我们需要将该yum源安装到linux机器上的yum源清单中,通过rpm -ivh mysql57-community-release-el7.rpm,安装之后,ls /etc/yum.repos.d/ -al可以查看到系统的yum源清单,更新yum源之后,我们可以通过yum list | grep mysql查看系统中相关的mysql的资源。更新yum源之后,我们就可以将上传到linux上的mysql yum文件删除掉了,这个.rpm文件现在就没什么用了。 (5)现在我们就可以使用yum命令一键安装mysql服务了,使用sudo yum install -y mysql-community-server,此时yum就会按照自己的yum源自动的帮我们一键安装MySQL服务,安装过程中可能会遇到密钥过期的问题,我们可以从网络中拿取新的密钥进行更新linux机器的密钥,rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022执行该指令即可更新Linux机器的密钥,更新之后重新yum安装MySQL服务即可。 安装成功之后,ls /etc/my.cnf可以看到my.cnf文件,并且netstat -nltp还可以看到守护进程mysqld,启动或者停止这样的守护进程mysqld,我们可以通过systemctl stop mysqld,systemctl start mysqld,systemctl restart mysqld(重启守护进程)。

上传好的yum源文件,以.rpm为文件后缀

将yum源安装到linux机器上的yum源清单中

安装MySQL服务之后,可以看到一个守护进程mysqld,该进程即为MySQL的服务进程,为我们提供MySQL数据存储服务。

在bin和sbin目录下分别存在两个可执行文件,一个是mysql,代表登录mysqld服务的客户端,一个是mysqld,代表提供网络数据存储服务的服务端。

3. (6)安装好MySQL的整个服务之后,我们就可以通过命令行式的客户端来使用和登录mysqld服务了,mysql -uroot -p即可登录MySQL服务,但在登录时由于我们没有密码,所以还需要将my.cnf配置文件的内容更改一下,在文件末尾加入一行skip-grant-tables,即跳过鉴权,这样在登录的时候,我们就不需要输入密码,直接连续点两下回车即可登录MySQL服务了,登录MySQL服务之后,show databases;即可看到当前数据库中已有的database。(注意修改my.cnf配置文件后,需要让配置的内容生效,但此时mysqld服务进程早就已经启动了,所以我们需要让mysqld守护进程重新启动一下,这样才能使跳过鉴权的操作生效)

4. 至此为止,我们就搞定了MySQL的登录问题,但还差一件事就是配置my.cnf文件,主要配置的是MySQL客户端和服务端的编码格式,我们统一使用utf8的编码格式,保证客户端和服务端使用的编码是一致的。 mysql客户端的编码格式我们先不设置,只设置mysqld服务端的即可,配置之后还是老样子,重启mysqld服务,让我们的配置生效即可。 (systemctl enable mysqld 和 systemctl daemon-reload可以设置mysqld服务为开机自启动,不过因为我们使用的是云服务器,云服务器不会关机,所以这个指令设置不设置都没什么区别,如果你用的是虚拟机,则可以设置。)

二、数据库基础

1.什么是数据库?(基于CS模式的一套数据存取的网络服务)

1. 使用命令行来登录MySQL,mysql -h127.0.0.1 -P3306 -uroot -p来进行登录,但今天我们的客户端和服务端都是在同一台linux机器上,上面的-h和-P选项可以不带,因为mysql客户端默认连接的就是本地的MySQL服务,另外my.cnf配置文件中已经有了mysqld服务的端口号3306,所以我们的客户端在连接MySQL服务时,是可以找到本地主机上的mysqld网络服务的。 所以实际在登录mysql服务时,只需要指明-u用户是谁,以及-p密码是什么即可,由于我们在my.cnf中加了skip-grant-tables,所以-p也不需要我们输密码,直接回车就可以登录。

2. MySQL是一种基于CS(client and server)模式的网络数据存储服务,提供了客户端mysql,以及服务端mysqld,客户端可以通过网络连接到服务器上,并向服务器发送SQL语句请求,服务器负责执行SQL语句,并将执行结果返回到客户端上。 服务器是数据库的管理者,负责存储,管理,维护数据库中的数据,同时MySQL支持多种客户端的连接方式,除了我们现在所使用的命令行式的客户端连接方式外,还支持图形化界面workbench,以及语言级别的API来连接mysql_init() + mysql_real_connect(),所以mysqld可以允许多个客户端同时连接到一个数据库服务器上,实现多个客户端之间的协同操作以及数据共享。 而我们口语上所说的数据库,大多数是指在内存中或磁盘中存储的特定结构组织的数据,表和表之间互相关联而成的数据存储结构,但实际上数据库是一套在内存上运行的网络服务,用于实现数据存取。

3. 存储数据用文件就可以了,为什么还要搞个数据库呢? (1)文件不利于数据的查询和管理,同时文件不利于存储海量数据,其实这两点说的是同一点。 因为普通的文件存储方式只适合于小规模的数据存储,例如存储文本文件,图像、视频等文件,一旦存储海量数据,文件不会对数据进行管理和组织,如果我们要查询海量数据中的某些数据时,则需要自己手动编写文件IO的代码,这太低效了,每次查询都需要重新编写文件IO的代码,同时文件存储方式也没有提供数据索引和查询功能,一旦查询,则需要在海量数据中一个一个遍历的查询,效率太低。 (2)文件非常不安全,因为文件没有加密和权限控制等方式,反观数据库通过权限,认证,加密等方式来保证数据的安全性。 (3)文件在程序控制中非常的不方便,想必这个缺点大家都感同身受吧,文件操作简直太恶心了,要处理读取内容末尾的\n,并且读取上来的内容也都是一大块放到缓冲区里的数据,同样没有对数据进行组织和管理。 所以数据库对我们来说相当于一个中间件,以往我们对数据进行存取,可能只能通过文件读写的方式来进行,但现在有了数据库之后,我们可以将自己的需求通过mysql客户端交给mysqld服务器,mysqld会和磁盘打交道,进行我们的sql语句的执行,从磁盘中拿取对应的数据或其他处理结果,将这个处理结果返回到mysql客户端,这样就完成了程序员对数据的存取需求。 程序员直接操纵mysql客户端即可完成对磁盘上数据处理的工作,不用在繁琐的进行文件IO,你给mysqld请求,mysqld给你返回结果。

2. Linux文件系统和数据库的关系 && 主流数据库

1. 实际上所谓的在MySQL中建立database,实际就是在对应linux文件系统中的/var/lib/mysql路径下创建一个目录,所谓的在database中建立一个或多个table,实际就是在linux的mysql路径下的目录中创建对应的文件。这些工作都是由谁做的呢?实际就是由mysqld服务器做的,服务器会在linux机器的磁盘上创建出对应的目录和文件。 所以数据库的本质就是文件,每个database都会对应linux磁盘上的一个文件,只不过这些文件不应该由程序员直接手动操控,而是应该由数据库mysqld服务器来进行操控,让mysqld来进行磁盘上数据的存取。

2. 下面这张图刻画了MySQL服务和Linux文件系统的关系,对于普通的数据我们可以直接操纵文件系统来处理磁盘上的数据,而对于需要管理和组织的数据,我们则通过数据库管理系统即CS模式下来进行数据的存取。 一般开发人员会对每个特定业务都分配一个database,在每个database内部会创建多个相互级联和组织到一起的表结构,用于存储该业务所需要的数据。

3. SQL Sever: 微软的产品,.Net程序员的最爱,中大型项目。 Oracle: 甲骨文产品,适合大型项目,复杂的业务逻辑,并发一般来说不如MySQL。 MySQL:世界上最受欢迎的数据库,属于甲骨文,并发性好,不适合做复杂的业务。主要用在电 商,SNS,论坛。对简单的SQL处理效果好。 PostgreSQL :加州大学伯克利分校计算机系开发的关系型数据库,不管是私用,商用,还是学术研 究使用,可以免费使用,修改和分发。 SQLite: 是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库 中。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的 低,在嵌入式设备中,可能只需要几百K的内存就够了。 H2: 是一个用Java开发的嵌入式数据库,它本身只是一个类库,可以直接嵌入到应用项目中 上面的数据库管理系统中,国内用的最多的还是MySQL,银行金融业用oracle比较多,MySQL的生态很完整,经过时间的考量,已经暴露出很多的bug,并且有相关活跃的社区修改这些bug,数据库也比较稳定。

3.MySQL架构 && SQL分类 && MySQL存储引擎

1. 除MySQL客户端外,MySQL服务器整体的架构分为三层。 第一层是连接管理,也就是connection pool连接池,这一层会进行连接处理connection handle,身份认证authentication,安全策略security,这一层也是和MySQL客户端打交道最近的一层,对MySQL客户端发起的连接做处理。 第二层是SQL语句的接口SQL interface,sql语句的解析器parser,以及sql语句的优化optimizer,因为MySQL的sql语句的标准格式是全大写的,而我们敲的sql语句一般是小写的,所以mysqld服务在收到sql语句之后,还要对sql语句做一定的优化optimizer,除此之外mysqld也有自己的caches缓存策略,比如某一个database使用innodb存储引擎时,该缓存层会开辟一大块的buffer pool用于数据的缓存,该缓存层可以很好的解决由于多次IO导致的程序性能降低问题,他可以根据局部性原理,在加载数据时,同时加载一批相关的数据,除了缓存数据之外,caches还会进行sql语句查询的缓存,以及表信息的缓存等,是很重要的一层。 第三层是支持热拔插的存储引擎,值得注意的是,这里的热拔插并不是指物理上的某些插头进行拔插,而是指软件层面上的支持动态添加,删除和替换存储引擎的能力,可以在数据库运行时,动态的添加或删除存储引擎,而无需停止数据库服务或重启服务器,实现数据的平滑迁移。 例如我们的某个database现在使用的是MyISAM存储引擎,可以支持大量的非事务性,大文件数据的存储和读取,如果我们想让该database的数据保证完整性和一致性,则需要使用innodb存储引擎,它可以支持ACID(Atomicity、Consistency、Isolation、Durability)的事务以及快速查找时需要的B+索引结构。 而这三层站在操作系统的角度来看依旧是应用层,应用层下面才会到内核层,也就是接近linux内核的文件系统,进程管理,驱动管理,内存管理等等。如果站在网络角度来看的话,那也是应用层,在下面才会到传输层。

2. MySQL的sql语句大体分为三类,分别是DDL(data definition language)数据定义语言,DML(data manipulation language)数据操纵语言,DCL(data control language)数据控制语言,在DML中又单独分了一个DQL(data query language)数据查询语言。 DDL:用来维护存储数据的结构,例如表table结构,数据库database结构,常用的sql语句有create drop alter DML:用来对结构中的数据内容进行操纵,常用的sql语句有insert delete update等,其中单独分出来的select语句就属于DQL。 DCL:主要负责权限和事务的管理,不负责处理库或表结构数据,也不负责处理库或表中存储内容的数据,主要进行一些连接用户的权限或事物的回滚提交等操作,常用的sql语句有grant、revoke、create user、commit,rollback等。

3. 存储引擎是MySQL数据存取服务的最重要的组成部分,是mysqld进行数据存储,为存储的数据建立索引,对数据进行CURD(create update read delete)等技术的具体实现方法,mysqld数据存储服务的核心实现就是依靠热插拔的存储引擎来实现的。 通过show engines就可以看到我们当前的MySQL服务使用的默认的存储引擎就是我们当时在my.cnf中配置好的InnoDB存储引擎,除InnoDB外,另一个常用的存储引擎就是MyISAM,我们主要学习和使用的是InnoDB存储引擎,因为他支持事物transaction,行级锁定row-level locking,可以支持高并发读写的场景,而MyISAM不支持事务和行级锁定,只支持表级锁定,也就是如果有客户端对表做CUD操作,则必须串行化执行,无法进行并发式的执行,这会降低效率。所以如果有大量读写并发的场景,则建议使用InnoDB存储引擎,该存储引擎支持行级锁定,只锁定表中的某一行数据,其他未锁定的行依旧可以进行高并发的CURD操作,效率会变得比较高,但同时会增加数据库系统的开销和负责度。

4. 下面是各个存储引擎的功能feature,包括存储空间限制storage limits,事务transaction,锁定的粒度大小locking granularity,多版本并发控制MVCC,B+树索引B-tree indexes,T+树索引T-tree indexes,哈希索引hash indexes,数据缓存data caches,索引缓存index caches,数据复制技术replication support,外键foreign key support,查询缓存query cache support等。

三、MySQL操作库

1.库结构的CURD操作

查看MySQL中所有的数据库:show databases;

创建数据库的指令和显示创建数据库时的指令

!40100 default… / 这个不是注释,表示当前mysql版本大于4.01版本,就执行这句话,其实就是设定数据库的编码集为utf8

删除数据库的指令。记住绝对不要以手动直接删除linux文件系统中目录的方式来删除数据库,打死都不要这么干,因为mysqld负责管理这些特殊的文件,程序员不应该干涉mysqld的工作,而应该通过mysql客户端发送sql语句的方式来对linux磁盘上的文件进行CURD。 注意:删除数据库这样的指令非常的危险,不要轻易的删除,因为删除数据库后是无法恢复出来的,除非你提前做了数据库的备份,这条sql语句就和rm -rf ./*这样的指令一样,非常的危险!请谨慎执行!

1. 上面的sql语句说完之后,我们需要来谈一个重要的话题,就是编码集charset和校验集collate,在创建数据库的时候指定这两个字段的值。 编码集指的是数据库存储数据时所使用的编码规则,校验集指的是数据库在查找数据进行数据比对的时候,所使用的比对规则。database必须保证编码集和校验集所使用的编码格式是统一的。

2. MySQL5.7默认的编码集和校验集分别是utf8和utf8_general_ci,在MySQL 8.0及以上版本中,utf8_general_ci被替换为utf8mb4_general_ci作为默认的校验规则,这样可以支持更为广泛的字符集和表情符号。

数据库支持的字符集和校验集,但默认都是utf8

配置文件中数据库的编码默认就是utf8

3. 除了使用默认的编码和校验规则之外,我们也可以在创建数据库的时候,指定编码和校验规则,例如下面创建数据库的时候,使用到了gbk的校验规则。

4. 下面对比了utf8_general_ci和utf8_bin校验规则不同时,数据库查询时所造成的查询结果的不同,其实就是区不区分大小写,默认数据库是不区分大小写的,也就是utf8_general_ci校验规则

5. 使用数据库:use database_name,确认当前自己在哪个数据库里面:select database(),修改数据库的编码或校验规则:alter database database_name charset=xxx或collate xxx 注意:大部分情况下我们都不会去修改数据库的编码或校验规则,只使用my.cnf配置文件中的编码规则即可。

2.库的备份与恢复 && 数据库的连接情况

1. 数据库的重命名MySQL是不支持的,并且这是非常合理的,因为数据库的名字是量级很重的,一旦数据库的名字发生改变,则上层所有使用数据库的代码都需要做出调整,代价特别大,所以一般在项目前期讨论协商的时候,一定要确定好数据库的命名等工作,等到项目开始开发的时候,就不要更改这些量级比较重的地方了。 除非万不得已,必须要对数据库重新命名的时候,一般会采用备份与恢复的方式来进行重命名,备份的指令:mysqldump -P3306 -u root -p 密码 -B 数据库名 > 数据库备份存储的文件路径,备份成功后,在指定的路径下面就会存在.sql文件,打开.sql文件其实就可以看到其中备份的内容,其实就是sql语句和相对应的数据。恢复数据库的指令:source 文件路径+文件名,恢复数据库实际就是将当初创建数据库时所执行的sql语句全部重新执行一遍,这样就恢复好数据库了。

2. 如果备份的不是整个数据库的所有内容,而是一张表,则可以通过指令:mysqldump -u root -p 数据库名 表名1 表名2 > 路径/mytest.sql,也可以备份多个数据库 mysqldump -u root -p -B 数据库名1 数据库名2 … > 数据库存放路径。 如果备份一个数据库时,没有带上-B参数, 在恢复数据库时,需要先创建空数据库,然后使用数据 库,再使用source来还原。所以如果你想对数据库重命名的话,则可以在备份数据库的时候,不带上-B参数,备份成功后,删除现有的数据库,然后在恢复数据库的时候,先自己创建一个数据库(指定自己想要的数据库名称),然后在执行source sql语句进行数据库内容的恢复。

3.查看数据库的连接情况

四、MySQL操作表

1.表结构的CURD操作

1. 创建表的时候,()内的内容为列名和列的属性,()后面的内容为表的属性字段,例如编码集,校验集,存储引擎等,myisam将数据和索引分开存储,innodb将数据和索引一块存储。等到后面我们会学到,MyISAM的主键索引和非主键索引都是非聚簇索引,而InnoDB的主键索引是聚簇索引,非主键索引是非聚簇索引。后面在学习到聚簇和非聚簇时,我们会详谈。

2. 查看表就是下面这三条sql语句,分号;和\G都可以作为sql语句的结束,只不过显示的方式不同,前者是以行为分隔符进行显示,后者是以二维形式的表结构来进行显示。

3. 修改表名:alter table old_table_name rename to new_table_name,to可以省略,直接rename 向表中新增一列:alter table table_name add 列名 列属性 after 表中的某一列名,如果不带after的话,则新增的一列默认是在表的尾部。 修改表中某一列的属性:alter table table_name modify 列名 新属性 删除表中的某一列:alter table table_name drop 列名 修改表中某一列的名字:alter table table_name change 新列名 新属性

4.删除表:drop table 表名 值得注意的是,删除表,删除库,修改库名,修改表名这样的操作都很危险,如果在项目开发一半的时候产品经理告知要修改表名或者库名,那就很有可能在上层出现逻辑问题或编译问题,这对程序员是一种莫大的伤害,所以在前期讨论项目构建的时候,一定要确定好库结构,表结构,库名,表名,等到项目开始开发的时候,这些就不要改动了。

2.对库结构和表结构操作的SQL语句的小总结(DDL语句)

1. 总结一下,如果我们要对表结构做修改,使用的关键字是alter,改表名字是rename,增加列是add,修改列属性是modify,修改列名是change,删除某一列是drop。 对库或表结构做查看的时候,一般会用到show和show create两个sql语句,对表结构信息查看还多了一个desc语句。 删除库或表,统一使用的是drop语句

2. 我们上面所学的都是DDL语句,即数据定义语言,不是DML,更不是DCL语句,在学习完数据类型之后,我们紧接着学习的就是DML语句,对表中存储数据的增删查改语句。

五、MySQL数据类型

1.数值类型

1.1 整数类型

1. 下面是MySQL中的整数类型,常用的数据类型是int,在MySQL里面定义列的时候,是列名在前,列属性在后,如果数据类型后面什么都没有带,则默认是有符号的,只有显示带了unsigned,则才是有符号的。

2. 在C/C++语言中,如果我们将一个整数初始化一个char类型的变量,则默认进行隐式类型转换,发生截断,然后进行存储,但在MySQL里面并不会这样,例如下面我创建了tinyint类型的num列,当我插入的数据是合法的时候,则可以顺利的插入到表中,而如果插入的数据不合法时,MySQL会直接拦截我们,不让我们做对应数据的插入,反过来,如果有数据插入到MySQL中,则已经插入的数据一定都是合法的数据。 所以在MySQL中,数据类型本身也是一种约束,约束使用者进行合法数据的插入,通过这样的约束就可以保证数据库里面数据的可预期性和完整性。

3. 实际在建表,给某一列字段分配具体数据类型的时候,一定要结合具体使用场景来分配,如果你分配的不够合理,则很可能会出现空间浪费的情况,比如某一列只需要1字节即可完成数据的存储,但你却用了bigint属性,那存储一条数据就会浪费7字节的空间,而数据库存储的数据又是海量的数据,最后浪费的空间则会非常巨大,平白无故给系统带来很大的消耗。 所以在实际分配数据类型时,一定要合理的结合具体使用场景来分配。

4. 还有一个常用的数值类型就是bit,我们可以用一个比特位来充当某些列字段的类型,bit位的个数最多是64位,如果在列名后面加bit不带括号指定位数的话,则默认是1bit,从右边插入数据的过程可以看到,当只有一个比特位的时候,插入的数据只能是0或1,其他数据均无法正常插入,被MySQL拦截。

在显示表中内容的时候,我们可能看不到类型为bit的列字段的值,其实主要是因为当存储的数据大小小于1字节时,utf8编码和ascll编码是相同的,而0和1在ascll编码中属于不可见字符,所以在显示表t3内容的时候,我们看不到online的字段值。如果想要显示,则可以通过函数hex()来进行显示,该函数可以将online字段改为16进制显示,这样就可以看到online的值了。

1.2 小数类型

1. float double decimal的使用方式均相同,float[(m, d)] [unsigned] : M指定显示长度,d指定小数位数,占用空间4个字节,decimal(m, d) [unsigned] : 定点数m指定长度,d表示小数点的位数,括号中都是两位,前者表示整体的小数长度,后者是小数点后面的位数。

2. 当类型为float(4,2)的时候,可以看到下面的数值越界测试,MySQL是允许小数部分进行四舍五入的进行插入的,但必须要满足四舍五入之后总体的长度位数不能超过4,下面插入的数据有正有负,允许插入的数据范围为-99.99到99.99,如果你插入的小数位数大于2,则先进行四舍五入,在四舍五入之后的数值如果还在数据范围内,则允许插入。

当数值类型加上unsigned修饰的时候,负数不允许插入,可插入的数值范围减半。

2. float的精度大约是7位,如果插入的数据大于7位的话,则实际保存在数据库中的数据位数可能会不准。

3. 如果你想让存储的数据的精度更高的话,则可以使用decimal数值类型,可以看到,当相同数值向不同类型的列字段f1和d1进行插入的时候,decimal存储的精度显然更高一些。(不同的MySQL版本,decimal的精度可能会有差异)

2.字符串类型

2.1 char和varchar

1. 当创建表的第二个列字段为char(2)的时候,可以看到两个汉字和两个字母都可以插入到表中,但三个字母却无法插入,如果这里的字符和C语言中的字符概念相同的话,那就是2个字节的大小,那就不应该插入两个汉字,因为两个汉字在utf8编码下共占用6字节,应该会溢出的呀! 所以MySQL中的字符和C/C++语言中的字符概念是不同的,MySQL中的字符指的是一个字节序列,这个字节序列可以由多个字节构成,例如一个字符,一个ascll字符,或一个四字节的象形文字,表情符号等等,都算是一个字节序列。 char最大允许255个字符长度进行插入,如果你想要更大的数值类型,则可以使用blob(binary large object)和text,blob适合存储二进制数据,例如图像,声音,视频等多媒体数据,text适合存储文本数据,例如文章,日志等数据。 文本数据在存储时,一般会先按照对应的编码格式,例如utf8或ascll等,进行文本数据的编码,然后将编码后的数据按照对应编码的二进制表示形式存储到磁盘上,在取数据时,按照对应的编码格式进行解码,即可得到原始的文本数据。

2. varchar是可变长度字符串,支持的最大字节数为65535,同时varchar还需要1-3个字节来记录数据的大小,所以有效字节数为65532,utf8中一个普通字符最大所占字节数为3字节,所以varchar的参数最大值是21844。

3. 21844个字符长度指的是表中一行的长度,如果表中一行里面还有其他的字段,则创建varchar时的参数还要比21844再小一些。值得注意的是,如果你使用某一数据类型,频繁的达到临界存储条件的话,则应该更换更大的数据类型进行存储。

4. char和varchar的使用要结合具体场景来看,比如存储某些长度不变的数据时,则可以直接使用char,如果要存储长度变化的数据时,则可以使用varchar,但同时要保证varchar能够存储的下长度变化最大时的数据。

2.2 日期和时间类型

1. 常用的日期时间类型分别为date,datetime,timestamp,前两个为固定值,一旦插入到表后,除非你用update语句进行修改,否则不会发生变化,而timestamp是时间戳,只不过这里的时间戳的表示形式是年月日时分秒,而不是一长串表示秒的数字,当时间戳的数值插入到表后,该时间戳会随着表中任意数值内容的改动而发生改动,换句话说,只要表中内容被修改,则时间戳会自动更新为当前最新的时间。 timestamp字段由自己的默认值,所以在插入数据的时候,我们可以不用管这一列的值,后面我们学到约束的时候,就知道Default字段的含义了。

当我对表中第一行信息更新的时候,timestamp自动更新为当前的时间。

2. 时间戳一般可以用来实现评论,比如某个用户发表了自己的评论,当他对自己评论做修改的时候,该评论对应的timestamp会自动更新。 比如下面的例子中,我将评论”C++好找工作吗?“修改为“学好的话肯定是好找工作的”,则对应的timestamp类型的time字段的值会自动更新为当前最新时间。

3. datetime时间日期类型一般用于记录某个固定的时间日期,比如员工的入职时间,办理身份证的时间,这些时间是不能随表的内容更改而更改的。 而date日期类型一般用于记录某个不需要时间,只需要日期的固定数值,例如你女朋友的生日,只需要记录日期即可,不需要记录几分几时几秒。

2.3 枚举和集合类型

1. enum是枚举类型,可以在枚举的选项中单选出一个作为数值插入到表中,set是集合类型,可以在集合的选项中多选或单选出某些数值插入到表中。 enum在插入数值时,除插入枚举所给的选项外,也可以插入每个选项值对应的数字,从1开始依次向后为每个选项对应的数字下标。 set在插入数值时,除插入集合所给的选项外,也可以插入每个选项值对应的数字,每个选项值通过唯一的比特位来标识,也就是位图,用一个比特位来标识当前选项是否被选中。

2. 可以看到在插入数据时,如果你插入的gender字段不在枚举选项里面,则MySQL会直接拦截你对数据的插入,这再一次说明了类型本身就是约束,同时也可以看到枚举选项也可以用数字下标来代替,例如12分别代表枚举选项中的男和女,下标一般从1开始,这里与C或C++语言有所不同。

插入set集合的选项时,如果要插入多个则需要用逗号分隔开来,注意不能含有空格,必须只有逗号来作为多个选项之间的分隔,同时所有选项外面用单引号括住,或双引号括住,无论是单引号还是双引号,MySQL都是支持的

3. 值得注意的是,在插入set选项时,是可以用0来作为数字插入的,只不过插入的是空串,在MySQL这里空串和NULL是由区别的,NULL指的是该列字段彻底为空,没有该列字段,如果赵六的hobby是NULL的话,则说明赵六没有hobby这一字段值,如果赵六的hobby是""的话,则说明赵六有hobby这一字段值,只不过hobby为空,这两个是不同的概念。 在插入set选项时,强烈不建议插入数字,因为插入数字的可读性太差。

4. 枚举和集合的查询,枚举在进行查询的时候,直接在where子句中添加筛选条件即可完成查询,不过where子句中的筛选条件是一种绝对的匹配,适用于枚举的严格匹配查询,因为枚举只能单选,比如gender只能有男或女,则匹配的时候直接绝对匹配即可。 如果在集合中进行查询时,则就不符合条件了,例如我想找出爱好中包括打篮球的人,如果使用where子句进行筛选的话,则查询出来的人的爱好就只有打篮球,所以仅仅使用where是不行的。还需要配合一个函数叫做find_in_set(sub,str_list) :如果 sub 在 str_list 中,则返回下标;如果不在,返回0;str_list 是用逗号分隔的字符串。 则使用select * from votes where find_in_set(‘打篮球’, hobby)即可查询到hobby里面包含打篮球的人,find_in_set会遍历表中所有人的hobby,只要包含打篮球字段,则返回大于等于1的值,则where条件判断为真,select此时会显示出来,如果不包含打篮球字段,则返回0,where条件判断为假,select就不会显示出来了,这也就是为什么枚举的下标是从1开始的了,因为MySQL中某些函数想要用0来作为查询结果是否存在的判断值。

find_in_set的第二个参数为以逗号分隔的字符串,也可以是set集合,或enum枚举,他俩也都是以逗号分隔的多个字符串。

六、MySQL表的约束

1.not null约束 && default约束

1. 约束的唯一目的其实就是为了保证数据库中数据的有效性,可预期性和完整性,一旦插入的数据不符合表约束,则MySQL直接拦截数据的插入,倒逼程序员向数据库中插入有效的数据。让数据库中的数据都是符合约束的。

1. not null一般约束的是,当我们在插入对应的列字段时,该列字段的数值不能为null值,必须是有效值,同时当我们创建一个表添加列字段的时候,如果什么属性都不带,则会有一个默认属性default,default的值为null,这点我们可以通过show create table xxx \G SQL语句看到。 同时null是指什么都没有,并且不参与任何计算。

2. other列什么属性都没有带,则sql默认会给他带上一个default属性,该属性字段值为null,所以在插入数据的时候,values的右边可以忽略掉other列,忽略掉这一列,则实际插入数据时,该列字段使用默认值null来进行插入。 我们也可以选择不忽略掉other列,如果不忽略的话,则使用我们自己插入的数据,不使用默认值,other列也没有not null约束,所以在插入数据的时候,我们也可以显示的插入null值。 通过下面的报错也可以看到default和not null分别控制的是什么,当我们忽略掉class_name或class_room列字段时,MySQL报错的是doesn’t have a default value,告诉我们该列字段没有默认值,所以你是不可以忽略这列字段的。 而当values左面的括号进行全列插入的时候,插入class_name或class_room列字段值为null时,此时MySQL报错的才是cannot be null,不允许为空值,因为有not null非空约束。

3. default默认值约束,如果用户在插入数据时,想要忽略这一列字段的插入,则可以使用default,例如一个程序员相亲网站,大部分用户肯定都是男性,所以我们可以默认用户的gender为男。 default的使用方式有两种,一种是忽略该字段插入,默认使用default的值,一种是不忽略该字段插入,手动的插入自己想要的值。

4. 当not null和default属性叠加到一块时,其实就是如果你忽略该列,则直接使用default的值,如果你不忽略该列,则插入的值不能为null值。就这么简单。

5. 有一些MySQL的默认行为还需要给大家说一下,当创建一个表的时,如果什么属性都不带,则默认会有一个default:null的属性,一旦添加任意一个属性,则MySQL给该列自带的default属性就会消失。 not null和default分别约束的是,插入数据的值不能为null和忽略该字段的插入时,直接使用default值。

2.comment约束 && zerofill

1. comment约束并没有什么实际的含义,在建表的时候,可以在列字段后面加上一些内容上的描述,此时就可以使用comment约束来实现。 不过这些字段值在desc查看表结构的时候,并不会显示出来,只有在show create table xxx显示创建表结构时的sql语句时候才会显示出来,所以comment的值不是给数据库看的,而是给数据库管理员(DBA)或维护数据库的程序员看的。

2. zerofill是关于显示方面的约束,并不会更改数据实际在磁盘上的存储结果,仅仅只是更改显示的结果而已,默认的int unsigned数值类型,在desc查看时,int后面会有个括号,里面的数字是10,其实10代表的是数字字符的个数,如果你在创建表的时候,不显式指定括号里面的数字的话,则MySQL默认会认为int unsigned是10位,此时如果给列字段增加zerofill,则显示出来的结果会变成10位的数字,高位用0来进行填充。

3. 如果显示的数字位数小于int括号里面的数字的话,则空余位全部用zero填充,如果显示的数字位数大于int括号里面的数字的话,该怎么显示就怎么显示,此时zerofill约束不起作用。 当你不指定int后面的括号时,如果是有符号int,则括号内的数字默认是11位,如果是无符号int,则括号内的数字默认是10位。 因为int是4字节,所以无符号int默认的最大数字字符个数就是10个,如果是有符号则还要多个符号字符,所以默认就是11位。

3.primary key约束 && auto_increment约束

1. primary key主键用来唯一的约束该列字段里面的数据,这些数据不能重复,同时也不能为空,并且主键约束的字段都是整数类型,不会是浮点数、字符串、日期时间等类型,一张表里面最多只能由一个主键。 例如在建表test_key的时候,一旦给id加上了primary key约束,则表还会自动的增加not null属性,这点可以通过show create table test_key\G看出来,sql优化后的主键标准格式为在表括号内的最后一行加上primary key(‘id’)。 如果在表中第二次插入id为1的数据,则MySQL会直接拦截,并报错duplicate entry ‘1’ for key ‘PRIMARY’,指的是条目1对于主键重复,不允许我们插入数据,这就是primary key的约束。

2. 除了在建表的时候添加主键,我们也可以在建表之后添加主键或删除主键,使用sql语句alter+drop primary key或alter+add primary key(xxx)。

3. 我们除了给一个字段添加主键外,也可以给多个字段同时添加上主键,这样的主键我们称之为复合主键(一张表确实只能有一个主键,但这一个主键可以添加到多列上) 例如id是学生的学号,course是课程的课号,我们不想让一个学生重复的选择一门课程多次,但我们可以允许一个学生选择多门课程,或不同的学生选择同一门课程,在这样的场景下,就适合用复合主键,在表中添加primary key(id, course)复合主键

4. 自增长auto_increment可以和主键或唯一键搭配使用,与主键相同的是:一张表中只能有一个自增长auto_increment,自增长的字段必须是整数。 当自增长与主键搭配使用时,我们称主键为自增主键。 建表的时候,可以在圆括号外面指定自增长的初始值,如果没指明也没有关系,默认从1开始,在插入数据的时候,我们可以忽略有自增长字段的列,该列会自动每次从当前字段中已有的最大值,加上1然后分配给新插入的数据。show create table时,也可以看到下一个插入数据时,对应的auto_increment的值。 实际上像QQ号这样的注册模式,使用的就是自增长,保证QQ号具有唯一性,不允许出现重复的QQ号

5. 与主键相同的是,一张表也只能有一个自增长,如果一张表出现多个自增长,则建表也会不成功。 除此之外还有一个函数last_insert_id(),该函数用于获取上次插入的自增长的值,如果上次是批量化插入的,则获取插入的第一条数据所对应的自增长的值。

4.unique key约束 && foreign key references约束

1. 一张表中往往有多个字段需要唯一性标识,一张表只能有一个主键,但一张表可以有多个唯一键,所以唯一键就可以很好的约束表中多个需要唯一性标识的字段,唯一键和主键比较相似,从功能上来讲,唯一键允许为空null,主键不允许为空null,不过空字段是不做唯一性比较的,判断表中唯一键是否重复时,NULL肯定是不作比较的,这非常合理。 例如student表中的唯一键约束的id,可以是多个NULL,因为我们知道NULL不参与任何比较和计算,所以可以出现id为多个NULL的情况。

2. 举一个例子,一张表中假设有两列信息,一个是员工的身份证号码,一个是员工的工号,这两个信息都需要唯一性标识,我们便可以将身份证号码设置为主键约束,员工工号设置为唯一键约束,一般而言,我们都会将主键设置成为和当前业务无关的字段,这样的话,当业务发生变化的时候,主键可以不用做过多的调整。

3. 一张表中,主键只能有一个,唯一键可以有多个,所以例如学生id,电话号码,QQ号码等都可以进行唯一键约束,如果你不想让唯一键中出现NULL值,则可以在唯一键约束的基础上再多添加一个not null非空约束。 设置为not null约束的唯一键从功能上来讲,已经和主键没有区别了,都是保证字段的唯一性,但从数量上来讲,一个表中主键只能有一个,唯一键可以有多个。从业务上来讲,主键一般设置为和当前业务无关的字段,唯一键一般设置为和当前业务挂钩的字段。

3. 外键约束是innodb存储引擎的一个重要特性,外键一般用于进行表和表之间的关联,用于约束具有关联性的表,比如下面的学生表和班级表,学生是隶属于班级的,比较合理的做法就是创建外键约束,外键为学生表中的class_id,引用自班级表中的主键列id。

4. 下面是外键约束的探究过程。 如果stu和class表之间没有外键约束的话,则向stu表中插入数据时,有可能误操作将一个学生插入到两个班级,或者将学生插入到不存在的班级,以及删除班级,但班级此时还有学生,如果不添加约束,则学生又到了不存在的班级中了,这些都是不合理的,所以显而易见,班级表和学生表之间一定需要某种约束关系,而这个约束实际就是外键约束!

5. 当建立外键约束后,外键为stu表中的class_id,引用自class表中的id,如果此时将学生插入到不存在的班级,或者删除某个班级,一个学生插入到两个班级等等不合逻辑的操作,都会被MySQL拦截掉,保证表与表之间正确的关联关系。 其实这里的外键,个人觉得和复合主键有那么一点点相似,必须保证外键和引用之间的唯一性,但外键的约束显然是要比复合主键更严格的,比如删除引用(引用中还存在着外键)是不被允许的,一个外键列中的字段只能配一个引用列中的字段,必须是一对一的,就像离散数学里面的双射关系一样,严格的一对一。

5.综合案例

1. 有一个商店的数据,记录客户及购物情况,由以下三个表组成: 商品goods(商品编号goods_id,商品名goods_name, 单价unitprice, 商品类别category, 供应商provider) 客户customer(客户号customer_id,姓名name,住址address,邮箱email,性别sex,身份证card_id) 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums) 要求: 每个表的主外键。客户的姓名不能为空值。邮箱不能重复。客户的性别(男,女)

2. 订单中的商品编号和客户编号需要外键约束,引用到goods和customer各自的goods_id和customer_id中。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、MySQL服务的安装
  • 二、数据库基础
    • 1.什么是数据库?(基于CS模式的一套数据存取的网络服务)
      • 2. Linux文件系统和数据库的关系 && 主流数据库
        • 3.MySQL架构 && SQL分类 && MySQL存储引擎
        • 三、MySQL操作库
          • 1.库结构的CURD操作
            • 2.库的备份与恢复 && 数据库的连接情况
            • 四、MySQL操作表
              • 1.表结构的CURD操作
                • 2.对库结构和表结构操作的SQL语句的小总结(DDL语句)
                • 五、MySQL数据类型
                  • 1.数值类型
                    • 1.1 整数类型
                    • 1.2 小数类型
                  • 2.字符串类型
                    • 2.1 char和varchar
                    • 2.2 日期和时间类型
                    • 2.3 枚举和集合类型
                • 六、MySQL表的约束
                  • 1.not null约束 && default约束
                    • 2.comment约束 && zerofill
                      • 3.primary key约束 && auto_increment约束
                        • 4.unique key约束 && foreign key references约束
                          • 5.综合案例
                          相关产品与服务
                          对象存储
                          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档