MySQL数据库学习笔记
发布于2020-04-29 13:06:52,更新于2021-10-27 20:52:24,标签:sql 文章会持续修订,转载请注明来源地址:https://meethigher.top/blog以下是个人牢骚。
有个场景,很可笑。
某上课场景
学生:老师,我的xx按你说的运行不了啊。
老师:你安装得不对,卸载了重新安。
其实是学生安装的是最新版,老师非要让学生下载老古董。更气人的是,某些老古董,都已经找不到完整的原程序了。
某面试场景
面试官:你用过什么数据库?
面试者:我们老师教过小海豚标志的数据库,我用得很熟练。
教我们的某个老师,自己就搞不懂,mysql是啥,sqlyog又是啥。教的时候,就把sqlyog当做mysql来操作了。
mysql是数据库,可以通过命令行来操作;sqlyog是数据库的界面可视化工具
大部分老师,是不懂得更新自己知识的,毕竟职业已经是铁饭碗,谁还去想,教的东西有没有用,学生到底学到了什么?
好老师有吗?当然有。一些刚入职教师行业的老师,还很理想化。就拿我某个老师来说,他一直说,教书育人是件很神圣的事,上课也要有仪式感。我们也都觉得这个老师好,但是他自己呢?工资低、同时也没有副业。还有的老师,兢兢业业备课,认认真真教书。就连期末学生给他送钱,求个及格,老师都拒绝了。过得清廉,然而他也只是个老师而已。
某些老师,教学混日子,上课出去抽根烟,出去撒泡尿,半节课就过去了。但是他自己有很多职称,有很多副业,有很多关系,有很多专利。你即使去问问题,他也不鸟你。学生确实没学到东西,但是他自己钱包赚得满满的。
当然,还有些老师,教学认真教,各种关系处得也很好,自己手头也有很多项目。这种老师要看自己机缘了。
本文以MySQL8.0+为例,仅做入门参考。具体内容,参照MySQL官方文档。
一、数据库概念
英文:DataBase 简称DB
概念:用于存储和管理数据的仓库
数据库的特点:
- 持久化存储数据。本质是一个文件系统
- 方便存储和管理数据
- 使用了统一的方式(SQL)操作数据库
常见的数据库:
全球数据库排名DB-Engines Ranking
- Oracle:收费的,大型关系数据库,Oracle公司的产品。Oracle收购Sun公司,收购MySQL
- MySQL:开源免费的数据库,小型关系数据库。被Oracle收购之后,开始收费
- 免费: 免费版本的具有开源协议,在免费版本上进行的任何修改所发布的软件,也必须是开源的(开源牛逼!)
- 收费: 如果你想将修改后的软件出售获利,就必须得购买收费版本才可以 。 此外,收费版本卖的不是软件,而是服务,当数据出现问题的时候,购买的服务可以帮助处理发生问题的数据。
- SQLServer:MicroSoft公司收费的中型关系型数据库。C#,.Net等语言常使用。
- DB2:IBM公司的大型关系数据库产品,收费的。常用在银行系统中
- SQLite:嵌入式的小型关系型数据库,内置到软件或系统中去,比方说浏览器。应用在Android手机端
- SyBase:已经淡出历史舞台。提供了一个非常专业的数据建模工具PowerDesigner
二、SQL概念
SQL:结构化查询语言(Structured Query Language ),其实就是定义了操作所有关系型数据库的规则。每一种数据库操作的方式存在不一样的地方,就类似于“方言”。
SQL通用语法:
- SQL语句可以单行或者多行书写,以分号结尾
- 使用空格和缩进来提高语句可读性
- SQL语句不区分大小写,关键字建议使用大写
- 注释
- 单行注释:– 注释内容 或者 # 注释内容(MySQL特有)
- 多行注释:/* 注释 */
1 | -- 单行注释 |
SQL分类:
- DDL(Data Definition Language)数据定义语言。用来定义数据库对象:数据库,表,列等。关键字:create, drop,alter 等
- DML(Data Manipulation Language)数据操作语言。用来对数据库中表的数据进行增删改。关键字:insert, delete, update 等
- DQL(Data Query Language)数据查询语言。用来查询数据库中表的记录(数据)。关键字:select, where 等
- DCL(Data Control Language)数据控制语言。用来定义数据库的访问权限和安全级别,及创建用户。关键字:GRANT, REVOKE 等
三、MySQL使用
数据库可视化操作工具:
- Navicat Premium(目前为止,感觉最好用的一款)
- SQLyog(最新版的界面依旧是上古风格,不过还是挺好用的,推荐)
- DBeaver(别人推荐,我还没用过)
题外话,讲讲使用技巧
Navicat查看sql语句
SQLyod查看sql语句
MySQL下载:地址
推荐解压版,拒绝傻瓜式。身为开发者,动手能力必须要强。我某同学,至今还以为mysql是个软件。我曾经给人安装了解压版,然后人家跟我说,这不是mysql,有海豚标志的才是mysql(可视化工具sqlyog的图标)。我就回了一句,哦,我还不太会安,你找别人吧。
常用命令行(进入到mysql的bin目录下):
mysql -u 用户名 -p 用户名 或mysql -u 用户名 -p; - - 连接数据库
show databases; - - 展示全部数据库
create database name; - - 创建name数据库
use name; - - 使用name数据库
show tables; - - 展示其中的表
create table name (id int,name varchar(20),age int); - - 创建name表,其中有3列,int型id列,varchar型长度为20的name列,int型age列
desc name; - - 查看name表的结构
source sql.sql; - - 执行本地的sql.sql文件
drop table name; - - 删除name表
drop database name; - - 删除name数据库
exit或quit; - - 退出数据库终端
windows下用命令行操作,是件极爽的事情,最进下载了一套数学视频,文件名都被打了小广告,cmd一键批处理,爽地不要不要的
本来想着写一篇cmd命令学习笔记,但奈何内容太庞大了,等哪天有足够的时间,来系统学习的话,我会写一篇的。
四、SQL操作
以下例子都是基于MySQL
4.1 DDL:操作数据库、表
操作数据库:CRUD
也就是所谓的增删改查
C(Create):创建
创建beauty数据库,判断是否存在,并设置字符集为UTF-8:create database if not exists beauty character set utf8;R(Retrieve):读取
查询所有数据库:show databases;U(Update):更新
查看数据库的字符集:show create database beauty;
修改数据库的字符集:alter database beauty character set gbk;D(Delete):删除
删除数据库:drop database if exists beauty;使用数据库:use beauty;
查看当前使用的数据库:select database();
操作表:CRUD
C(Create):创建
语法:create table 表名 (列名1 数据类型1,列名2 数据类型2,…,列名n 数据类型n);创建表:create table girls(id int,name varchar(20),score double(4,1),birthday date,insert_time timestamp);
复制表:create table 表名 like 被复制的表名;
R(Retrieve):读取
查询所有表:show tables;
查询表结构:desc 表名U(Update):更新
修改表名:alter table 表名 rename to 新表名;
查看表的字符集:show create table 表名;
修改表的字符集:alter table 表名 character set utf8;
添加一列:alter table 表名 add 列名 数据类型;
修改列的类型:alter table 表名 modify 列名 新类型;
修改列名称 类型: alter table 表名 change 列名 新列名 新类型;
删除列:alter table 表名 drop 列名;D(Delete):删除
删除表:drop table if exists 表名;
数据类型的注意点:
double(4,1)表示总长度为4的数,其中小数有1位
date表示日期,只包含年月日,yyyy/MM/dd。我在开发starry的时候,发现在ios的safari中,只识别yyyy/MM/dd,而不识别yyyy-MM-dd,使用的时候注意。
datetime表示日期,包含年月日时分秒,yyyy/MM/dd HH:mm:ss
timestamp表示时间戳,包含年月日时分秒,yyyy/MM/dd HH:mm:ss。有种说法,“如果将来不给这个字段赋值,或者赋值为null,则默认使用系统当前时间,来自动赋值。”,经测验无效。
4.2 DML:增删改表中数据
添加数据
语法:insert into 表名(列名1,列名2,…,列名n) values(值1,值2,…,值n);
1 | INSERT INTO fairy(id,NAME,score) VALUES(1,'胡列娜',80.1); |
注意:
- 列名和值,要一一对应。
- 如果表名后,不定义列名,则默认给所有列添加值。insert into 表名 values(值1,值2,…,值n);
- 除了数字类型,其他类型都需要使用引号(单双引号都可以)引起来
删除数据
语法:delete from 表名 where 条件;
1 | DELETE FROM fairy WHERE NAME='水冰儿'; |
注意:
- 如果不加条件,则会删除表中所有记录。
- 如果要删除所有记录。
- delete from 表名; 不推荐使用,有多少条记录,就会执行多少次删除操作。效率比较低。
- truncate table 表名; 推荐使用,先删除表,然后再创建一张一模一样的表。效率比较高。
修改数据
语法:update 表名 set 列名1=值1,列名2=值2,…,列名n=值n where 条件;
1 | UPDATE fairy SET NAME='水月儿' WHERE id=2; |
注意:
- 如果不加任何条件,则会将表中所有记录全部修改
4.3 DQL:查询表中记录
导入数据:
1 | USE `beauty`; |
语法:select 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件限定 order by 排序规则 limit 分页限定
基础查询
- 多个字段的查询
select 字段名1,字段名2,… from 表名;
如果查询所有字段,可以使用 * 来替代字段列表 - 去除重复
DISTINCE关键字 - 计算列
一般可以使用四则运算,来计算列的值
IFNULL(表达式1,表达式2) 表达式1是指需要判断为NULL的字段,表达式2是指NULL的替换值。 - 起别名
AS关键字,也可以省略
1 | -- 多个字段查询 |
条件查询
where子句后跟条件
运算符
运算符 | 含义 |
---|---|
>、<、<=、>=、=、<> | <>在 SQL 中表示不等于,在 mysql 中也可以使用!=,没有==这个运算符 |
BETWEEN…AND… | 在一个范围之内,如:between 100 and 200 相当于条件在 100 到 200 之间,包头又包尾 |
IN(集合) | 集合表示多个值,使用逗号分隔 |
LIKE ‘张%’ 或 LIKE ‘张_’ | 模糊查询。%指多个占位符,_指单个占位符 |
IS NULL 或 IS NOT NULL | 查询某一列为 NULL 的值,注:不能写=NULL |
AND 或 && | 与,SQL 中建议使用前者,后者并不通用。 |
OR 或 || | 或 |
NOT 或 ! | 非 |
代码
1 | -- 查询年龄大于等于20岁的 |
排序查询
语法:order by 排序字段1 排序方式1,….;
排序方式:
- ASC:升序排。默认值
- DESC:降序排。
注意:
- 如果有多个排序条件,则当前面的值一样时,才会去判断第二条件
代码:
1 | -- 按age升序排 |
聚合函数
将一列数据作为一个整体,进行纵向计算。
- count:计算个数
一般选择非空的列:主键
可以通过count(*),但实际开发中,少用这个 - max:计算最大值
- min:计算最小值
- sum:计算和
- avg:计算平均值
注意:聚合函数的计算,排除NULL值
解决方案:
- 选择不包含非空的列进行计算
- IFNULL(grade,0)
代码:
1 | -- 显示总数 |
分组函数
语法:group by 分组字段;
注意:
- 分组之后查询的字段:分组字段或者聚合函数;
- where和having的区别?
- where在分组之前进行限定,如果不满足条件,则不参与分组;having在分组之后进行限定,如果不满足条件,不会被查询出来
- where后跟不可跟聚合函数;having可以进行聚合函数的判断
1 | -- 按照性别分组,求总人数,并且求不同组的平均等级 |
分页查询
语法:limit 开始的索引,每页查询的条数;
公式:开始的索引=(当前的页码-1)x每页显示的条数
注意:limit是MySQL的一个“方言”。不同的数据库分页操作是不同的
1 | -- 从第1条数据开始,显示3条 |
多表查询
笛卡尔积:A、B两个集合,取这两个集合的所有组成情况。要完成多表查询,要消除无用的数据。
内连接
使用内连接的要求:
- 从哪些表中查询数据
- 条件是啥
- 查询哪些字段
隐式内连接
语法:select 字段列表 from 表名列表 where …;
1 | -- 查询两张表所有数据 |
显式内连接
语法:select 字段列表 from 表1 [inner] join 表2 on 条件;
[]这个符号表示可以省略的意思
1 | -- 查询两张表所有数据 |
外连接
左外连接
语法:select 字段列表 from 表1 left [outer] join 表2 on 条件;
1 | -- 查询所有人信息,如果有位置,则查询位置信息;如果没有位置,则不显示 |
左外连接:
查询的是左边表的所有数据,以及连接表的交集部分
右外连接
语法:select 字段列表 from 表1 right [outer] join 表2 on 条件;
1 | -- 右外连接,跟上面左外连接的结果一样,写法的区别就是表的顺序,左换右,右换左了 |
右外连接:
查询的是右边表的所有数据,以及连接表的交集部分
内连接与外连接区别
此处的外连接就用左外连接来代表了。左外连接在查询时,会将join左边的内容全部都查出来,右外连接会将join右边的内容全部都查出来,原理其实是一样的。
unit表
unit_id | unit_type | unit_name |
---|---|---|
1 | 1 | aaa |
2 | 1 | bbb |
3 | 1 | ccc |
4 | 1 | ddd |
5 | 1 | eee |
person表
person_id | person_name | unit_id |
---|---|---|
1 | 小明 | 1 |
2 | 小红 | 1 |
3 | 小黄 | 1 |
4 | 小光 | 4 |
5 | 小明 | 2 |
6 | 小明 | 3 |
内连接语句
1 | select |
结果
外连接语句
1 | select |
结果
区别:
- 内连接如果关联的字段没有值,比如null,是不会查出来的
- 外连接会保证进行外连接的一方全查出来,也就是说,即使它关联的字段为null,也是会查出来的。
子查询
概念:查询中嵌套查询,称嵌套的这个查询,为子查询
1 | -- 查询等级最高的人 |
子查询的不同情况
- 子查询的结果是单行单列的
子查询可以作为条件,使用运算符去判断。>,>=, <, <=, = - 子查询的结果是多行单列的
子查询可以作为条件,使用运算符in来判断 - 子查询的结果是多行多列的
子查询可以作为一张虚拟表参与查询
1 | -- 子查询结果是单行单列的 |
联合查询
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。
将两个查询结果合并
1 | SELECT column_name(s) FROM table1 |
举例工作中的一个需求,一张审批表,要分页查询审批信息。
审批状态有审批中、变更中、审批不通过、变更不通过、通过5种状态。
- 审批通过之后,会生成infoResAllCode。每个审批通过后的资源信息的infoResAllCode是不同的
- 提交变更,会新生成一条数据,infoResId也是新的
- 变更通过之后,旧数据修改历史版本字段为1,表示是历史版本了。变更后的作为新数据。
看时序图会好理解一点。
需求听起来很简单,分页查询审批数据,只查询出最新版本的那条。
像审批,多次不通过之后,有一条通过的,应该只查出来最新的那条记录。这个好整,虽然审批不通过的时候,infoResAllCode是空的,但因为infoResId是唯一的,取本infoResId中最新时间即可。
像变更,多次变更通过之后,会生成新的infoResId,但此时infoResAllCode又是唯一的了,需要取infoResAllCode中的最新时间来显示。
这是两条SQL语句,如果想要通过一次分页查询出来,就需要用到union。这是一个解决思路,但是并不好。
最后的解决办法,添加一个字段oldInfoResId,save的时候,将oldInfoResId存为当前infoResId。这样在查询时,只需要根据oldInfoResId分页查询最新时间的那条就行。
练习
数据库的架构如图
1 | -- 需求: |
4.4 DCL:管理用户与权限
管理用户
查询用户
SELECT * FROM USER;
注意:通配符%表示可以在任意主机使用用户登录
1 | -- 查询用户 |
添加用户
create user ‘用户名‘@’主机名’ identified by ‘密码’;
1 | -- 创建用户 |
删除用户
DROP USER ‘用户名‘@’主机名’;
1 | -- 删除用户 |
修改用户密码
1 | -- 修改密码 |
管理权限
查询权限
1 | -- 查询权限 |
授予权限
1 | -- 授予权限 |
撤销权限
1 | -- 撤销权限 |
刷新权限
1 | -- 刷新权限 |
4.5 约束
概念:对表中的数据进行限定,从而保证数据的正确性、有效性和完整性
约束:
- 主键约束:primary key
- 非空约束:not null
- 唯一约束:unique
- 外键约束:foreign key
非空约束
NOT NULL,值不能为NULL
- 创建表时,添加非空约束
- 已创建表,添加非空约束
- 删除非空约束
代码:
1 | -- 创建表时添加非空约束 |
唯一约束
UNIQUE,值不能重复(但是允许存在多个NULL)
- 创建表时,添加唯一约束
- 已创建表,添加唯一约束
- 删除唯一约束
代码:
1 | -- 创建表时,添加唯一约束 |
主键约束
含义:表示非空且唯一
一张表只能有一个字段表示主键。主键就是表中记录的唯一标识。
主键约束:
- 创建表时,添加主键约束
- 已创建表,添加主键约束
- 删除主键约束
代码
1 | -- 创建表时,添加主键约束 |
自动增长
概念:如果某一列是数值类型的,使用auto_increment 可以完成自动增长
自动增长:
- 创建表时,添加主键约束,并完成自动增长
- 已创建表,添加自动增长
- 删除自动增长
1 | -- 创建表时,添加自动增长 |
注意:
自动增长是根据上一条数据的大小来增加的。比防说上一条是9,如果不传值,下一条就会是10
外键约束
一张表的数据,会过于冗余,我们可以将其进行拆分,然后再将两张表,通过外键关联起来。
外键约束:
创建表时,添加外键约束
1
2
3
4
5create table 表名(
....
外键列
constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称)
);已创建表,添加外键约束
删除外键约束
级联操作(级联更新和级联删除)
1
2
3
4
5-- 添加级联操作
alter table 表名 add constraint 外键名称 foreign key (外键列名称) referencs 主表名称(主表列名称) on update cascade on delete cascade
--也可以只添加其中某一个,也可以都添加,
--实现的功能,就是在删除外键表的内容的时候,主键表与其相关的内容也会一起被删掉
代码:
1 | -- 创建表时,添加外键约束 |
五、数据库的设计
5.1 多表之间的关系
分类
- 一对一关系:如人和身份证号。一个人只有一个身份证号,一个身份证号对应一个人。开发中很少使用
- 一对多(多对一)关系:如部门和员工。一个部门对应多个员工,一个员工对应一个部门。
- 多对多关系: 如学生跟课程。一个课程对应多个学生,一个学生对应多个课程。
这三种关系可以表示所有的事务之间的关系。
实现关系
- 一对一(一般情况合成一张表)
一对一关系实现,可以在任意一方添加唯一外键指向另一方的主键。 - 一对多(多对一)
在多的一方建立外键,指向一的一方的主键。 - 多对多
多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键
案例
代码
1 | -- 创建旅游线路分类表 tab_category |
打开架构设计器,就会自动生成如下关系图
一对多:可以通过左外连接查询
多对多:可以通过在左外连接获得的数据基础上,再次使用左外连接。
具体的教程参照mybatis
1 | select * from role |
5.2 数据库设计的范式
概念:设计数据库时,需要遵循的一些规范。要遵循后边的范式要求,必须要遵循前边所有的范式要求
分类:
- 第一范式
- 第二范式
- 第三范式
- 其他范式
第一范式
第一范式理解:每一列都是不可分割的原子数据项。
像这样的一张表,就满足第一范式了,但是也存在问题
- 存在非常严重的数据冗余(重复):姓名、系名、系主任
- 数据添加存在问题:添加新开设的系和系主任时,数据不合法
- 数据删除存在问题:如果有人毕业了,删除信息时,会将系一起删掉。
第二范式
第二范式理解:在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖)
函数依赖:A–>B,如果A属性(属性组)的值,可以唯一确定B属性的值。则成B依赖于A。例如,学号–>姓名;(学号,课程名称)–>分数
完全函数依赖:A–>B,如果A是一个属性组,则B属性值的确定需要依赖于A属性组中的所有的属性值。例如,(学号,课程名称)–>分数
部分函数依赖:A–>B,如果A是一个属性组,则B属性值的确定只需要依赖于A属性组中的某一些值即可。例如,(学号,课程名称)–>姓名
传递函数依赖:A–>B,B–>C,如果通过A属性(属性组)的值,可以确定唯一B属性的值,再通过B属性(属性组)的值可以确定唯一C属性的值,则称C传递函数依赖于A。例如,学号–>系名,系名–>系主任
码:如果在一张表中,一个属性或者属性组,被其他所有属性所依赖,则称这个属性(属性组)为该表的码。例如,在上表中的码,就是(学号,课程名称)。
- 主属性:码属性组中的所有属性
- 非主属性:除码属性组的属性
详细了解,请移步这里
现在根据第二范式的理解,在1NF基础上基础上消除非主属性对主码的部分函数依赖。
第三范式
第三范式理解:在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
其他范式
巴德斯科范式(BCNF)、第四范式(4NF)和第五范式(5NF)
六、数据库的备份与还原
数据库的备份和还原目的:防止出现问题,导致数据丢失的情况。
6.1 命令行
备份语法:mysqldmp -u用户名 -p密码 数据库名称 > 保存的路径
还原语法:
- 登录数据库
- 创建数据库
- 使用数据库
- 执行文件:source 文件路径
6.2 可视化工具
不同的可视化工具,具体操作不同,不多赘述
七、事务
7.1 事务的了解
概念
如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
举个例子,支付宝转钱。A给B转5块钱,成功的话,A账户金额-5,B账户金额+5。如果在A账户减少金额,或者在B账户增加金额的过程中出错,则所有事件回滚。
事务的操作
具体操作
- 开启事务
- 回滚
- 提交
开启事务:start transaction;
回滚:rollback;
提交:commit;
1 | -- zs给ls转账500 |
事务提交的两种方式:
- 自动提交
MySQL就是自动提交的,然而Oracle默认是手动提交的。
一条DML(增删改)语句会自动提交一次事务。 - 手动提交
需要先开启事务,再提交
修改事务的默认提交方式:
- 查看事务的默认提交方式:SELECT @@autocommit; – 1代表自动提交 0代表手动提交
- 修改默认提交方式:set @@autocommit=0;
7.2 事务的四大特征
ACID特征:
- 原子性(atomicity):是不可分割的最小操作单位,要么同时成功,要么同时失败。
- 持久性(durability):当事务提交或者回滚后,数据库会持久化地保存数据。
- 隔离性(isolation):多个事务之间,相互独立。但是,真实的情况下,事务之间是相互影响的,所以,我们要了解事务的隔离级别
- 一致性(consistency):事务操作前后,数据总量不变。
7.3 事务的隔离级别
概念:多个事务之间是隔离的,即相互独立的。但是,如果多个事务,操作同一批数据,则会引发一些问题,设置不同的隔离级别,就可以解决这些问题。
存在问题:
- 脏读:事务B执行过程中,修改了数据X,在未提交的时候,事务A来读取数据X,而事务B进行了回滚,那么此时事务A读取的数据就是错的,叫脏读。
- 虚读(不可重复读):事务A读取了数据X,而事务B修改了数据X,当事务A再次进行读取时,发现数据不匹配,这叫做虚读。
- 幻读:事务A根据条件X,查询出了N条数据,此时,事务B又添加了M条数据,其中有几条是在条件X范围内的,事务A再次查询时,发现多出来了几条数据,这叫做幻读。
脏读
幻读
隔离级别:
- read uncommited
含义:读未提交
产生的问题:脏读、不可重复读、幻读 - read commited(Oracle中默认隔离级别)
含义:读已提交
产生的问题:不可重复读、幻读 - repeatable read(MySQL中默认隔离级别)
含义:可重复读
产生问题:幻读 - serializable
含义:串行化(相当于把表锁上,A事物不提交,B事物是没法查询得到的)
可以解决任何问题
注意:
隔离级别从小到大,安全性越来越高,但是效率越来越低。我们要选择合适级别,既保证相对比较安全,又能保证效率较高
修改数据库的默认隔离级别:
- 查询隔离级别:
mysql5.6-5.7:select @@tx_isolation;
mysql8.0+:select @@transaction_isolation; - 设置隔离级别:set global transaction isolation level 级别字符串;
修改隔离级别之后,查询,如果没有改变。需要断开连接,重新连接之后,才会查出来。
八、触发器
本篇内容是做课程设计时,需要用触发器,由此就来总结一下。参考文章
8.1 概念
定义:触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合。
作用:协助应用在数据库端确保数据的完整性。
举例,比如我现在有两个表,unit和person表,person与unit通过unitid进行外键约束。当创建person就需要在其对应的unit表中更新总人数字段,我们可以通过编写程序语言逻辑来实现,如果通过触发器,会自动更新字段,更容易了。
触发器的类型
- INSERT型触发器:在执行insert、load data、replace语句时触发
- UPDATE型触发器:在执行update语句时触发
- DELETE型触发器:在执行delete、replace时触发
load data语句是将文件的内容插入到表中,相当于是insert语句
replace语句在一般的情况下和insert差不多,但是如果表中存在primary或者unique索引的时候,如果插入的数据和原来的primary key或者unique相同的时候,会删除原来的数据,然后再增加一条新的护具。
可以理解成,replace在没有重复的时候,相当于insert;若有重复,则会删除原来的,再执行insert
8.2 语法
要素
- 触发器名称
- 触发时机
- BEFORE:之前
- AFTER:之后
- 触发事件
- INSERT
- UPDATE
- DELETE
- 表名:需要建立触发器的表名
- 执行语句
- 一条SQL语句
- 多条SQL语句,通过begin和and包含起来
创建触发器
1 | -- 一条执行语句 |
以上图为例,创建触发器,来实现person的数据发生变化时,修改unit表的总人数
1 | CREATE TRIGGER insert_trigger AFTER INSERT ON person FOR EACH ROW |
在执行多条语句的时候,触发器中间的sql语句分支是用;
来分割的。如果有多个触发器的话,最后也是需要加一个结束符号。而MySQL默认是以;
作为结束执行语句,为避免与触发器的内部分支起冲突,我们可以通过使用DELIMITER $
来将结束符号修改为$
一般用在命令行的时候会这样,直接使用可视化工具,可以不用写
1 | DELIMITER $ |
可以通过导出sql文件,来进行查看。
删除触发器
1 | -- 删除触发器 |
定义变量
在begin…end中可以自定义变量,但是只能在begin…end中使用
语法
1 | -- 在begin...and中定义变量 |
New&Old
NEW和OLD使用
- NEW:表示将要或者已经增加(或修改或删除)的数据,用于INSERT、UPDATE型触发器
- OLD:表示将要或者已经被删除的数据,用于UPDATE、DELETE型触发器
语法
1 | -- 新增或修改行的某列数据 |
8.3 案例
需求
当在users中插入一条数据江厌离
,就会在logs中生成一条日志信息江厌离 is created
。
创建users表
1 | DROP TABLE IF EXISTS `users`; |
创建logs表
1 | DROP TABLE IF EXISTS `logs`; |
实现
1 | DROP TRIGGER IF EXISTS `user_log`; |
所有的触发器都存在information_schema数据库下的triggers表中
九、存储过程
9.1 概念
理论概念,看看就行
存储过程:类似于java代码中的方法,可以直接调用,来实现某些功能逻辑。有参数跟返回值
Navicat中描述的就挺合理,一个函数代替了,哈哈
本质不就是个可调用的方法嘛
优点:
- 代码可复用
- 代码精简一致
- 可维护性高
缺点:
- 可移植性差
- 使用于模块较小的功能:跟代码一样,每个方法功能尽量小,这样既易维护,又方便使用
9.2 快速入门
直接上sql语句
1 | -- 删除存储过程 |
参数类型
- IN:传递给存储过程
- OUT:从存储过程传出
- INOUT:对存储过程传入和传出
OUT
1 | DROP PROCEDURE IF EXISTS getGrades; |
在测试的过程中,发现
select name into username from memeber;
和
select name from memeber into username;
最后的效果是一样的,所以,这两条语句是等价的
IN
1 | drop procedure if exists getNameById; |
用sqlyog运行的时候,把字符串所占的字节也输出了,我就特意百度了一下,字节为啥有的2两个,有的占3个
原因是字符集的原因,gbk中,英文占1字节(Byte,简记为B),汉字占2字节;utf-8,英文占1个字节,汉字占3个字节。可以参考这篇文章