六一?作为一个大小孩当然是快快乐乐搞技术啦~在这篇文章中,荔枝会梳理SQL语句的基本语法以及MySQL中的函数、约束。多表关系以及查询、事务和事务隔离级别等内容,大致内容归属于MySQL基础知识,荔枝又弄了一篇万字长文哈哈哈哈,可以当学习笔记噢
前言
一、MySQL是什么?
二、mysql基础配置
三、SQL的基本语法
3.1 SQL分类
3.2 DDL语句
3.3 DML语句
3.4 DQL语句
3.5 DCL
四、函数
4.1 字符串函数
4.2 数值函数
4.3 日期函数
4.4 流程控制函数
五、MySQL约束
5.1 一个建表实例:
5.2 外键约束
六、多表查询
6.1 多表关系
6.2 多表查询
6.2.1 连接查询
6.2.2 子查询
七、事务
7.1 事务的操作
7.2 事务的四大特性(ACID)
7.3 并发事务引发的问题
7.4 事务的隔离级别
总结
MySQL数据库是一个关系型数据库(RDBMS),关系型数据库是一种建立在关系模型基础上,由多张相互连接的二维表组成的数据库。简单理解数据库其实就是存放数据的容器,常见的关系型数据库还有Oracle,相比之下MySQL是一个中小型关系型数据库适合个人开发者而且是社区版免费的哈哈哈哈。
window环境下直接安装即可,官网地址:https://downloads.mysql.com/archives/installer/,后续需要添加一下系统环境变量。
mysql启动
net start mysql
mysql停止
net stop mysql
mysql [-h 服务器ip] [-P 端口号默认是3306] -u root -p
分类 | 说明 |
---|---|
DDL | 数据定义语言,用来定义数据库对象(数据库,表,字段) |
DML | 数据操作语言,用来对数据库表中的数据进行增删改 |
DQL | 数据查询语言,用来查询数据库中表的记录 |
DCL | 数据控制语言,用来创建数据库用户、控制数据库的访问权限 |
全称是Data Definition Language,是一种数据定义语言,用来定义数据库对象(数据库,表,字段)
数据库操作
查询所有的数据库
SHOW DATABASES;
查询当前的数据库
SELECT DATABASE();
创建
CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则];
删除
DROP DATABASE[IF EXISTS]数据库名;
使用
USE 数据库名;
表操作——查询
查询当前数据库中的表
SHOW TABLES;
查询表结构
DESC 表名
查询指定表的建表语句
SHOW CREATE TABLE 表名
表操作——创建
CREATE TABLE表名(
字段1字段1类型[COMMENT字段1注释],
字段2字段2类型[COMMENT字段2注释],
字段3字段3类型[COMMENT字段3注释],
......
字段n字段n类型[COMMENT字段n注释]
)「COMMENT表注释1];
例子:
CREATE TABLE `deliever` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`f_id` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '配送食物的唯一标识',
`author` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '需配送的用户信息',
`avator` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '用户头像',
`courier` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '快递员信息',
`departure` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '配送的出发地',
`destination` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT '目的地',
`start_time` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '出单时间',
`estimated_time` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '预计配送时间',
`status` TINYINT(1) NOT NULL DEFAULT '1' COMMENT '订单状态,1:未接单;2:已接单;3:已完成;',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='配送抢单表'
表操作——数据类型
数值类型
分类 | 大小 | 有符号(SIGNED)范围 | 无符号(UNSIGNED)范围 | 描述 |
---|---|---|---|---|
TINYINT | 1byte | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 bytes | (-32768,32767) | (0,65535) | 大整数值 |
MEDIUMINT | 3 bytes | (-8388608,8388607) | (0,16777215) | 大整数值 |
INT或INTEGER | 4 bytes | (-2147483648,2147483647) | (0,4294967295) | 大整数值 |
BIGINT | 8 bytes | (-2^63,2^63-1) | (0,2^64-1) | 极大整数值 |
FLOAT | 4 bytes | (-3.402823466E+38,3.402823466351E+38) | 0和(1.175494351E-38,3.402823466E+38) | 单精度浮点数值 |
DOUBLE | 8 bytes | (-1.7976931348623157E+308,1.7976931348623157E+308) | 0和(2.2250738585072014E-308,1.7976931348623157E+308) | 双精度浮点数值 |
DECIMAL | 依赖于M(精度)和D(标度)的值 | 依赖于M(精度)和D(标度)的值 | 小数值(精确定点数) |
字符串类型
类型 | 大小 | 描述 |
---|---|---|
CHAR | 0-255 | 定长字符串 |
VARCHAR | 0-65535 | 变长字符串 |
TINYBLOB | 0-255 | 不超过255格字符的二进制数据 |
TINYTEXT | 0-255 | 短文本字符串 |
BLOB | 0-65535 | 二进制形式的长文本数据 |
TEXT | 0-65535 | 长文本数据 |
日期时间类型
类型 | 大小 | 范围 | 格式 | 描述 |
---|---|---|---|---|
DATA | 3 | 1000-01-01至9999-12-31 | YYYY-MM-DD | 日期 |
TIME | 3 | -838:59:59至838:59:59 | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901-2155 | YYYY | 年份 |
DATETIME | 8 | 1000-01-01 00:00:00至9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 4 | 1970-01-01 00:00:01至2038-01-19 03:14:07 | YYYY-MM-DD HH:MM:SS | 时间戳、混合日期和时间 |
表操作——修改
添加字段
ALTER TABLE表名 ADD字段名 类型(长度)[COMMENT注释][约束];
修改指定字段的数据类型
ALTER TABLE表名 MODIFY 字段名 新数据 类型(长度);
修改字段名和字段类型
ALTER TABLE表名 CHANGE 旧字段名 新字段名 类型(长度)[COMMENT注释][约束];
修改表名
ALTER TABLE 表名 RENAME TO 新表名;
表操作——删除
删除字段
ALTER TABLE 表名 DROP 字段名;
删除表
DROP TABLE [IF EXITS] 表名;
删除指定表并重新创建该表
TRUNCATE TABLE 表名;
DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增删改操作。
添加数据
给指定字段添加数据
INSERT INTO 表名(字段名1,字段名2,...)VALUES(值1,值2,…);
给全部字段添加数据
INSERT INTO 表名 VALUES(值1,值2,…);
批量添加数据
INSERT INTO 表名(字段名1,字段名2,…) VALUES(值1,值2,…),(值1,值2,…),...;
INSERT INTO 表名 VALUES(值1,值2,),(值1,值2,...),(值1,值2,…),...;
修改数据
UPDATE 表名 SET 字段名1=值1,字段名2=值2,... [WHERE 条件];
删除数据
DELETE FROM 表名 [WHERE条件]
DQL英文全称是Data Query Language(数据查询语言),数据查询语言,用来查询数据库中表的记录,在DQL中我们需要的是掌握不同的查询语法,主要用到的是:
执行顺序:
SELECT
字段列表
FROM
表名列表
WHERE
条件列表
GROUP BY
分组字段列表
HAVING
分组后条件列表
ORDER BY
排序字段列表
LIMIT
分页参数
基本查询
SELECT * FROM 表名;
SELECT 字段1,字段2,... FROM 表名;
设置别名
SELECT 字段1 [AS 别名] FROM 表名;
去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;
条件查询
SELECT 字段列表 FROM 表名 WHERE 条件列表;
举个例子:
查询年龄等于18或20或40的员工信息
select from emp where age 18 or age 20 or age =40;
select from emp where age in(18,20,40);
查询姓名为两个字的员工信息_ %(一个下划线代表一个字符)
select from emp where name like '__'
查询身份证号最后一位是X的员工信息
select from emp where idcard like '%X'
聚合函数和分组查询
函数 | 功能 |
---|---|
count | 统计数量 |
max | 最大值 |
min | 最小值 |
avg | 平均值 |
sum | 求和 |
聚合函数语法
SELECT 聚合函数(字段列表) FROM 表名;
分组查询语法
SELECT 字段列表 FROM 表名[WHERE条件] GROUP BY 分组字段名[HAVING分组后过滤条件];
举个例子:
查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址
select workaddress,count(*) from emp where age 45 group by workaddress having count(*)>=3;
where.与having区别
排序查询
语法
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2;
asc升序(默认)
desc降序
分页查询
SELECT 字段列表 FROM 表名 LIMT 起始索引,查询记录数
起始索引 = (要查询的页数-1)*每页数据数
DQL语句的执行顺序:
FROM
表名列表
WHERE
条件列表
GROUP BY
分组字段列表
HAVING
分组后条件列表
SELECT
字段列表
ORDER BY
排序字段列表
LIMIT
分页参数
DCL英文全称是Data Control Language(数据控制语言),用来管理数据库用户、控制数据库的访问权限。
用户管理
查询用户
USE mysql;
SELECT FROM user;
创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
删除用户
DROP USER '用户名'@'主机名';
权限控制
查询权限
SHOW GRANTS FOR '用户名'@'主机名';
授予权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM ‘用户名'@'主机名';
MySQL中内置了很多字符串函数,比较常见的有如下几种:
函数 | 功能 |
---|---|
CONCAT(S1,S2) | 字符串拼接 |
LOWER(str) | 将字符串中的字符全部转化成小写 |
UPPER(str) | 将字符串中的字符全部转化成大写 |
LPAD(str,n,pad) | 左填充,用pad填充str直至长度为n |
RPAD(str,n,pad) | 右填充 |
TRIM(str) | 去掉字符串头部和尾部的空格 |
SUBSTRING | 截取字符串 |
函数 | 功能 |
---|---|
CELL(X) | 向上取整 |
FLOOR(X) | 向下取整 |
MOD(X,Y) | 返回x/y的模 |
RAND() | 返回0-1内的随机数 |
ROUND(x,y) | 求参数x的四舍五入值,小数保留y位 |
函数 | 功能 |
---|---|
CURDATE() | 返回当前日期 |
CURTIME() | 返回当前时间 |
NOW() | 返回当前日期和时间 |
YEAR(date) | 获取指定date的年份 |
MONTH(date) | 获取指定date的月份 |
DAY(date) | 获取指定date的日期 |
DATE_ADD(date,INTERVAL num type) | 在指定日期的基础上增加num(年/月/日),这取决于type |
DATEDIFF(date1,date2) | 返回两个日期之间的天数 |
函数 | 功能 |
---|---|
IF(value,t,f) | 如果value为true,则返回t,否则返回f |
IFNULL(value1,value2) | 如果value1不为空,返回value1,否则返回value2 |
CASE WHEN val1 THEN [res1]..ELSE default END | 如果vall为true,返回resl,..否则返回default默认值 |
CASE expr WHEN [val1 THEN [res1]..ELSE default END | 如果expr的值等于val1,返回resl,.否则返回default默认值 |
首先要清楚约束是什么,约束是作用于表中字段上的一种规则,在实际应用场景中为了保证数据库中数据的正确性、有效性和完整性,我们使用约束限制存储在表中的数据。约束的常见分类有以下几种:
约束种类 | 描述 | 关键字 |
---|---|---|
非空约束 | 限制该字段的数据不能为nu | NOT NULL |
唯一约束 | 保证该字段的所有数据都是唯一、不重复的 | UNIQUE |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | PRIMARY KEY |
默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值 | DEFAULT |
检查约束(8.0.16版本后) | 保证字段值满足某一个条件 | CHECK |
外键约束 | 用来让两张表的数据之间建立连接,保证数据的一致性和完整性 | FOREIGN KEY |
create table user(
id int primary key auto_increment comment'主键', #主键约束+自增
name varchar(10) not null unique comment'姓名', #非空约束+唯一约束
age int check(age>0&&age<=120) comment'年龄', #检查约束
status char(1) default'1' comment'状态', #默认约束
gender char(I) comment'性别'
)comment'用户表;
外键用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
##添加外键语法
#创建表时添加外键
CREATE TABLE表名(
字段名数据类型
...
[CONSTRAINT] [外键名称] FOREIGN KEY (外键字段名) REFERENCES 主表(主表列名);
#修改表添加外键
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表(主表列名);
#删除外键
ALTER TABLE 表名 DROP DOREIGN KEY 外键名称
##例子:
#创建外键
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id);
#删除外键
alter table emp drop foreign key fk_emp_dept_id;
删除/更新行为
种类 | 描述 |
---|---|
NO ACTION | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除更新。(与RESTRICT一致) |
RESTRICT | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(与NO ACTION一致) |
CASCADE | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录。 |
SET NULL | 当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为ull(这就要求该外键允许取null) |
SET DEFAULT | 父表有变更时,子表将外键列设置成一个默认的值(Innodb不支持) |
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update cascade on delete cascade;
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update set null on delete set null;
项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为如下三种:
在多表查询时,我们需要使用select*同时从两张表中去查询,这时候会出现无效的笛卡尔积的情况,因此我们需要在多表查询时消除这种多余的笛卡尔积从而达到我们查询数据的要求。这时候可以使用where限定条件(比如令一张表的外键指向其绑定的主键)。多表查询主要分为连接查询和子查询,其中连接查询分为内连接、外连接和自连接。
内连接
##内连接查询语法:
#隐式内连接
SELECT 字段 列表 FROM 表1,表2 WHERE 条件;
#显式内连接
SELECT 字段 列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件...;
外连接
#左外连接
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件;
相当于查询表1(左表)的所有数据包含表1和表2交集部分的数据
#右外连接
SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 条件;
相当于查询表2(右表)的所有数据包含表1和表2交集部分的数据
##例子
#表结构:emp,dept
#连接条件:emp.dept_id=dept.id
select e.*,d.name from emp e left outer join dept d on e.dept_id=d.id;
select e.*,d.name from emp e left join dept d on e.dept_id=d.id;
#查询dept表的所有数据,和对应的员工信息(右外连接)
select d.*,e.* from emp e right outer join dept d on e.dept_id=d.id;
自连接
##自连接查询语法:
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件;
##两个例子:
#查询员工及其所属领导的名字
#表结构:emp
select a.name,b.name from emp a,emp b where a.managerid=b.id;
#查询所有员工emp及其领导的名字emp,如果员工没有领导,也需要查询出来
#表结构:emp a,emp b
select a.name '员工',b.name '领导' from emp a left join emp b on a.managerid=b.id;
联合查询
对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。实现联合查询的条件是查询多张表的列数必须保持一致,否则会报错。
SELECT 字段列表 FROM 表A
UNION [ALL]
SELECT 字段列表 FROM 表B;
ps:注意union和union all的区别,由于联合查询就是将两次查询的结果直接进行拼接并输出,所以结果中
可能会有重复的数据,而要实现去重就直接选择union即可。
SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任何一个。
语法
SELECT FROM t1 WHERE column1 =(SELECT column1 FROM t2);
按结果分类:
标量子查询
子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询成为标量子查询。
常用的操作符:= <> > >= < <=
select * from emp where dept_id=(select id from dept where name='销售部');
列子查询
操作符 | 描述 |
---|---|
IN | 在指定的集合范围之内,多选一 |
NOT IN | 不在指定的集合范围之内 |
ANY | 子查询返回列表中,有任意一个满足即可 |
SOME | 与ANY等同,使用SOME的地方都可以使用ANY |
ALL | 子查询返回列表的所有值都必须满足 |
子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。
常用的操作符:IN、NOT IN、ANY、SOME、ALL
例子:
##查询比财务部所有人工资都高的员工信息
#查询所有财务部人员工资
select id from dept where name='财务部';
select salary from emp where dept_id=(select id from dept where name='财务部');
#比财务部所有人工资都高的员工信息
select * from emp where salary > all(select salary from emp where dept_id(select id from dept where name ='财务'))
行子查询
子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。
常用的操作符:=、<>、IN、NOT IN
##查询与"张无忌”的薪资及直属领导相同的员工信息:
#查询”张无忌”的薪资及直属领导
select * salary,managerid from emp where name='张无忌';
--b.查询与"张无忌”的薪资及直属领导相同的员工信息;
select * from emp where (salary,managerid)=(select salary,manlagerid from emp where name ='张无忌')
表子查询
子查询返回的结果是多行多列,这种子查询称为表子查询。
常用的操作符:IN
##查询与"鹿杖客”,“宋远桥”的职位和薪资相同的员工信息
#查询”鹿杖客”,"宋远桥”的职位和薪资
select job,salary from emp where name ='鹿杖客'or name ='宋远桥';
#查询与”鹿杖客”,“宋远桥”的职位和薪资相同的员工信息
select * from emp where (job,salary) in (select job,salary from emp where name='鹿杖客'or name='宋远桥');
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。也就是说,如果开启事务后查询结果没有发生异常,则会提交事务;一旦出现异常就会抛出并执行事务回滚的操作,将原来修改过的数据进行恢复,比较典型的场景就是银行转账。
方式一:修改事务的提交方式
#查看/设置事务提交方式
SELECT @@autocommit #查看事物的提交方式是否是手动提交,手动提交是0,自动提交是1
SET @@autocommit=0; #绘画指令:设置手动提交
#设置手动提交事务之后必须要执行commit进行提交事务
COMMIT
#回滚事务:业务操作出现异常必须执行回滚事务
ROLLBACK
方式二:
#开启事务
START TRANSACTION 或 BEGIN;
#执行事务操作
...
...
...
...
#如果事务操作没有出现异常就进行事务的提交,否则执行事务回滚
#提交事务
COMMIT
#回滚事务
ROLLBACK;
需要注意的是在默认的事务隔离级别下,这两种方式在异常出现时候均不会使数据库中的数据变更。
并发事务问题一般出现在由多个并发事务同时对同一数据库进行操作所引发的:脏读、不可重复读、幻读的问题。
问题 | 描述 |
---|---|
脏读 | 一个事务读到另一个事务还没有提交的数据 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同 |
幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,出现例如主键冲突问题。 |
针对上面我们了解到的并发事务所出现的问题,我们可以通过设置事务的隔离级别来避免这些问题,事务隔离级别分类如下:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted | 1 | 1 | 1 |
Read committed(Oracle默认) | 0 | 1 | 1 |
Repeatable Read(MySQL默认) | 0 | 0 | 1 |
Serializable | 0 | 0 | 0 |
事物的隔离级别从上到下依次增强,但性能却依次减弱。隔离级别最低的数据库处理性能最强,但数据的安全性却最弱,因此在实际应用场景中我们需要根据业务需求来权衡选择。
查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
设置事务隔离级别
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
这里需要注意的是,当我们设置事务的隔离级别为Serializable时候数据库是如何解决幻读的问题的:现在假设事务A在开启一个事务并往一个空表中查询一个主键ID为2的数据,之后开启一个事务2往相同的表中插入一个主键为2的数据,这时候我们可以看到会话的窗口出现了停滞,这时因为我们将事务A的隔离级别设置为Serializable后只有等到A提交了事务或者回滚了事务之后,事务B才能对数据表进行操作,这也是串行化隔离级别解决幻读问题的所在。
在这篇文章中,荔枝主要分享了自己学习MySQL基础知识的笔记,了解这些其实就足够承担简单的增删改查的操作了,接下来荔枝也会继续梳理学习MySQL进阶知识的笔记,希望能帮助到有需要的小伙伴,最后祝所有大小孩六一快乐哈哈哈哈~~~
今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~