系列文章目录
前言
本文介绍了MySQL数据库的基本概念和SQL操作。主要内容包括:1.基本概念部分解释了MySQL的客户端-服务器结构、请求响应机制、数据存储方式(内存与硬盘区别);2.SQL操作部分详述了数据库的创建、查看、选择和删除命令,介绍了常用的数据类型(整型、浮点型、字符串、时间戳等)以及数据表的基本操作;3.重点讲解了MySQL表的增删查改操作,包括新增数据的多种方式、查询操作(全列查询、表达式查询、条件查询等)、修改和删除数据的语法。文章还特别强调了全列查询的风险以及排序、分页等查询技巧。
一、基本概念
MySQL 是一个数据库软件;
MySQL 是一个 "客户端-服务器" 结构的软件;
客户端(Client):主动发起请求的一方;
服务器(Server):被动接收请求的一方,服务器往往是需要 7 * 24 小时运行的;
请求(Request):客户端给服务器发起的数据;
响应(Response):服务器给客户端返回的数据;
MySQL 的本体是服务器,服务器负责存储和管理数据;存储数据的位置是硬盘;
内存和硬盘的区别:
-
内存速度快,硬盘速度慢;
-
通常一台计算机上的内存空间小,硬盘空间大;
-
内存价格贵,硬盘价格便宜;
-
内存中存储的数据是易失的,内存中的数据程序掉电或者重启就会丢失,硬盘中存储的数据是持久保存的;
使用数据库中存储的数据,通常数据量比较大,并且需要持久化存储,因此需要将数据存在硬盘上,MySQL 属于这种;但也有数据库是将数据存储在内存上的,追求速度的最大化;
二、SQL操作
操作数据库的命令,也称为 "SQL 语句",也可以理解成是一种编程语言;
1. 数据库操作
数据库是一个逻辑上的数据集合;
一个 MySQL 服务器程序可以在硬盘上组织保存很多数据(多个数据库);
MySQL 是通过表来组织数据的;
关键字:SQL 中有特定含义的单词,数据库名,表名,列名都不能和关键字重复;
SQL 的关键字是大小写不敏感的;
创建数据库:
sql
create database 数据库名;
-- 避免数据库已经存在,导致再创建数据库的时候出现 sql 报错
create database 数据库名 if not exists;
-- 指定字符集
create database 数据库名 charset utf8;
查看数据库:
sql
-- 列出当前的 mysql 服务器上有哪些数据库
show databases;
其中更改 mysql 配置,可以通过名为 mysql 的数据库设置;
选中数据库:
sql
use 数据库名;
数据库中最关键的操作就是针对表进行增删查改,表是从属于数据库的,要针对表操作,就需要先选中数据库;
删除数据库:
sql
drop database 数据库名;
2. 常用的数据类型
数据库中整型:
tinyint(1 byte), smallint(2 byte), int(4 byte), bigint(8 byte);
对应 java 中的 Byte, Short, Int, Long;
数据库中浮点型:
float(M, D):小数的长度是 M,小数点后的位数是 D,占用 4 字节;
**double(M, D):**小数的长度是 M,小数点后的位数是 D,占用 8 字节;
对应 java 中的 Float 和 Double;
float 和 double 是 IEEE 754 中定义的浮点数,存在一定的精度误差;
**decimal(M, D):**小数的长度是 M,小数点后的位数是 D,是精度更高的浮点数;
使用 decimal 表示小数,精度更高,但是运算速度会变慢,占用空间也更多;
对应 java 中的 BigDecimal;
数据库中的字符串:
**varchar(size):**size 指的是最多存储几个字符,是个可变长的字符串,最大长度不超过 size;
text:长文本数据,最多 64k 字节;
mediumtext:中等长度文本数据;
blob:二进制的长文本数据,最长 64k 字节;
数据库中的时间戳:
**datatime:**8 个字节的时间戳;
timestamp:4 个字节的时间戳;
对应 java 中的 java.util.Data(只能表示年月日),java.sql.TimeStamp(毫秒级时间戳);
时间戳:以 1970 年 1 月 1 日 0 时 0分 0 秒作为基准,当前时刻和基准时刻的 秒数/毫秒数/微秒数 之差;
3. 数据表操作
要针对数据表操作,需要先选中数据库,use 数据库名;
创建表:
sql
create table 表名(列名 类型, 列名 类型...);
-- 如果确实想让表名/列名 和关键字一样,可以使用反引号把表名/列名 引起来
create table `表名`(`列名` 类型, `列名` 类型...);
查看该数据库中的所有表:
sql
show tables;
查看指定表的结构:
sql
desc 表名;
删除表:
sql
drop table 表名;
三、MySQL 表的增删查改
1. 新增
在表中新增数据的时候,要注意值要和数据表中的列要匹配(个数和类型都要匹配);
sql
insert into 表名 values(值, 值......);
插入数据既可以插入所有列,也可以指定列插入:
sql
insert into 表名(列名, 列名...) values(值, 值...);
其它列会按照默认值进行填充;
也可以一次插入多行记录:
sql
insert into 表名 values(值, 值...), (值, 值...)...;
一次插入多行记录,比每次插入一行记录分多次插入效率更高;
每次插入数据,客户端和服务器都需要交互一次,多次插入就需要多次交互,效率比不上一次交互;
注意事项:
插入字符串时,可以使用单引号,也可以使用双引号,因为 sql 中没有字符的概念;
插入日期时,要使用指定格式的字符串,例如"2022-02-02 12:00:00";
如果要插入的时间就是当前时刻,可以使用 now() 这个函数;
2. 查询
1. 全列查询
sql
-- 全列查询
select * from 表名;
* 代指所有列;
注意:全列查询是一个危险操作,由于 mysql 是一个 "客户端 - 服务器" 结构的程序:
-
IO 方面:客户端通过网络向服务器发起请求,服务器接收到请求后会读取硬盘,如果当前表中存储的数据非常多时,会导致 IO 占满,其它需要使用 IO 的程序就会非常慢;
-
网络方面:服务器向客户端返回响应时,会把网卡的带宽也跑满,其它客户端想通过网络访问服务器时,也会非常慢;
2. 指定列查询
sql
-- 指定列查询
select 列名, 列名... from 表名;
3. 表达式查询
在查询的时候,写作由列名构成的表达式,把这一列的所有行都带入到表达式中,参与运算;
sql
-- 表达式查询
select 表达式 from 表名;
注意:这个表达式运算只是个临时结果,并不会改变数据库中的数据;
4. 带别名的查询
可以针对表达式,列以及表名指定别名进行查询;
sql
-- 指定别名
select 列名/表达式 as 别名 from 表名;
5. 去重
使用 distinct 修饰某个列/多个列(值相同的行只会保留一个);
sql
-- 对列进行去重
select distinct 列名 from 表名;
6. 排序
把行进行排序,需要明确排序规则:
- 需要明确针对哪个列进行比较;
- 需要明确是升序还是降序;
sql
-- 按照列排序
select 列名 from 表名 order by 列名 asc/desc;
默认是升序排序,asc 可以省略;
排序还可以针对表达式进行排序:
sql
-- 针对表达式排序
select 列名 from 表名 order by 表达式;
select 列名/表达式 as 别名 from 表名 order by 别名;
还可以指定多个列排序:
sql
-- 指定多个列排序
select 列名1, 列名2 from 表名 order by 列名3, 列名4;
-- 排序时可以指定升序或者降序
select 列名1, 列名2 from 表名 order by 列名3 desc, 列名4;
上述语句的含义是:
-
先按照列名 3 排序,如果列名 3 的值相同,再按照列名 4 排序;
-
先按照列名 3 降序排序,如果列名 3 的值相同,再按照列名 4 升序排序;
注意:
排序是针对临时数据进行排序的,不会改变 mysql 服务器上数据存储的顺序;
如果 sql 不加 order by,查询出来的顺序是不确定的,数据是无序的;
如果不加 order by,代码不应该依赖查询出来的数据的顺序开展逻辑;
如果排序的列没有被查询出来,也不会影响排序的正确性;
7. 条件查询
指定条件,按照条件进行筛选;
sql
-- 条件查询
select 列名 from 表名 where 条件;
where 条件的原理:
遍历表的每一行记录;
把每一行的数据分别带入到条件中进行筛选;
如果条件成立, 这个记录就会被放到结果集合中;
如果条件不成立,这个记录就会被跳过;
如果有 order by,会在所有的行都被获取到之后(表达式都计算完了),再针对所有的结果进行排序;
注意:如果别名的定义是在 select 列名后面,那不能在 where 中使用,因为是先执行 where 里面的条件,后执行 select 列名后面的语句;
不常见的比较运算符:
<=> 可以比较 null 和 null,null <=> null 为 true;
between a1 and a2:查找落在 [a1, a2] 范围中的,注意两遍都是闭区间;
in (o1, o2, o3...) :只要是在括号里的元素,就返回 true;
like:模糊匹配,%可以表示多个字符,_表示一个字符;
and,or:and 的优先级大于 or 的优先级,不确定优先级的时候推荐加括号来确定优先级;
8. 分页查询
sql
select 列名 from 表名 limit 记录数量 offset 记录下标;
记录数量表示要查询出几条数据;
记录下标表示从第几条记录查询(从 0 下标开始计数);
比如:
sql
select 列名 from 表名 limit 3 offset 3;
表示从 3 下标开始查询 3 条记录,也就是第 3,4,5 这 3 条记录;
3. 修改
sql
-- 修改
update 表名 set 列名 = 值 where 条件;
where 条件 - 用于限制要修改哪些行数据;
可以修改筛选出来的多行数据,但有可能修改不成功;
可以一次修改多个列的值:
sql
-- 修改多个列的值
update 表名 set 列 = 值, 列 = 值 where 条件;
此时 "=" 就是赋值的意思;
注意:
"=" 在 set 后面是赋值的意思,在 where 后面是比较的意思;
update 语句中如果不写条件,就会修改所有行;
4. 删除
把符合条件的记录从表中删除掉;
sql
-- 删除
delete from 表名 where 条件/order by/limit;
注意:
不指定任何条件,就是删除整个表;
drop table 是删除了表,也删除了表里的记录;
delete from 只是删除了表里的记录,但是空表还在;