目录
[toc]
一、课程介绍
1.数据库的事务机制
以前,MySQL4.0不支持事务机制,所以,那时的MySQL保存的是不重要的低价值数据,就像现在的NoSQL数据库一样。
自从MySQL5.0具有了事务机制,电商、金融等系统开始使用MySQL来保存高价值的数据。比如,阿里巴巴的OceanBase就是在MySQL5.0基础上修改来的。
事务的重要性体现在:ACID四个属性。
undo和redo日志、开启事务、提交事务、回滚事务
2.数据的导出与导入
比如,将笔记本中的MySQL数据,导入到台式机的MySQL里。直接拷贝覆盖数据目录,粗暴危险。两者创建的用户并不相同,会导致台式机的目录账户被覆盖丢失。
SQL文件的导出与导入
TXT文档的导出与导入
还是没有明白:既然用户不相同,为啥还是覆盖呢?
二、MySQL数据库的事务机制
2.1 重要性:直接操作数据文件很危险
我们平时修改重要文件,通常会先备份一下,然后在副本里修改。数据库也是如此。
数据的写入直接操作数据文件,是一种非常危险的行为。
比如,用UPDATE语句,给员工涨工资。突然,系统重启,就搞不清哪些记录修改了,哪些记录没有修改。
2.2 利用日志文件,来实现间接写入
日志文件就像是数据文件的一个副本。
MySQL中与事务机制有关的日志文件有两个:undo日志文件和redo日志文件。
undo日志文件:原数据文件的拷贝副本
redo日志文件:原数据文件的拷贝副本+全部已完成的记录修改,保存在里面
即便同步过程出现了停电、死机等突发状况,因为有redo日志文件的存在,再次同步即可。
2.3 事务(Transaction)概念
1.关系型数据库系统与事务
RDBMS=SQL语句+事务(ACID)
其中:
- 关系型数据库系统(RDBMS),使用了关系模型的数据库系统
- 之前很多章节,已经学习了SQL语句
接下来,就是学习事务。
2.概念
事务就是一个或多个SQL语句组成的整体,要么全部执行成功,要么全部执行失败。
比如,系统为新注册的用户发放代金券。结果是:要么用户注册成功,领取了代金券;要么用户没有注册成功,也没有领取代金券。如果出现了其他结果,即:用户注册成功,但是没代金券,用户没注册成功,但是,领取了代金券,这两种意外情况是不可能接受的。
2.4 事务案例
为了裁撤10部门:先把该部门中的MANGER员工调往20部门,其他的员工被调往30部门,然后删除10部门?
分析:
- 用到了两条SQL语句:UPDATE语句、DELETE语句。默认情况下,数据库会为每一条SQL写入语句,自动开启和关闭事务,这会导致可能出现两个意外情况;
- 因为只有更新和删除两条写入命令,要么全部执行成功,要么全部执行失败。不可能有其他结果。所以,两条语句必须是原子的、不可分割。因此,应该是使用事务,将两者包裹为一个整体,手动开启和关闭事务。
假如一些特殊原因,事务不能继续提交,那么就应该将事务回滚。
比如,抢购秒杀商品,虽然抢到了商品订单,但是支付晚了,这个事务就必须回滚,不能同步提交。
事务的回滚,对MySQL来说,是非常简单的。只需要把undo日志文件和redo日志文件中数据做一下标记即可。这些被标记的数据,就不会被同步到数据文件中。
2.5 利用SQL语句来管理事务
默认情况下,MySQL执行每条SQL语句(准确:写入的语句)都会自动开启和提交事务。
为了让多条SQL语句纳入到一个事务之下,可以手动管理事务。
1.语法
SQL语句的操作,如果想持久化到数据文件中,那么就用COMMIT来提交事务;
如果不想持久化,那么就执行事务的回滚,不同步到数据文件中。
2.案例应用
(1)没有提交同步时:
START TRANSACTION; # 手动开启一个事务
DELETE FROM t_emp; # 删除的操作只在日志文件中进行
DELETE FROM t_dept; # 只要不提交COMMIT来同步,原数据文件就不会有影响
SELECT * FROM t_emp; # 查询的操作,也是在日志文件中进行的
SELECT * FROM t_dept; # 所以,结果是查不到的
结果集:已删除,查询不到
实际上,在原数据文件中:
(2)有提交同步时:
START TRANSACTION;
DELETE FROM t_emp;
DELETE FROM t_dept;
SELECT * FROM t_emp;
SELECT * FROM t_dept;
COMMIT; # 提交同步
不仅临时的结果集查询不到数据,而且原数据文件中的数据,也被真正的删除,查询不到
其中,这个COMMIT是将最终结果提交同步给原数据文件, 非中间的过程数据。
(3)有回滚时
START TRANSACTION;
DELETE FROM t_emp;
DELETE FROM t_dept;
SELECT * FROM t_emp;
SELECT * FROM t_dept;
ROLLBACK; # 回滚,以上的全部,整体标记,不同步了
2.6 事务的四个特性:ACID
1.原子性
对数据的操作,要么全部成功,要么全部失败,没有中间状态。
2.一致性
不管什么时候,有多少并发的事务在执行,运行结果一定不会歧义。
比如,ABCD四个人,每个人的银行账户都存了500元。在同一时刻,进行转账:不管相互之间怎么转、赚多少钱,四人资金总额一定是2000元。
原理:阻止事务之间相互读取临时数据。()
3.隔离性
每个事务只能看到自己事务内的相关数据,从而不受其他并发事务的影响。
4.持久性
事务一旦提交同步,就是永久性的。即使发生宕机,仍然可以依靠事务的日志文件来完成数据的持久化。
三、事务的四个隔离级别
一般情况下,事务的ACID四个特性,是有利的。
但是,数据库的事务都是并发执行,因为隔离性的问题会给某些特定的业务场景带来问题。
因此,下面介绍在事务并发执行的条件下,怎么去修改事务的隔离级别,来满足特定业务的要求?
3.1四个隔离级别
默认情况下,MySQL是不允许事务之间,相互读取临时数据的。
但是,在某些特殊场合下,我们要允许事务之间能读取到一些临时数据。
以上场景不讲晦涩术语,而是结合真实的业务场景,来加深理解。
3.2 READ UNCOMMITTED
1.语法
READ UNCOMMITTED : 可以读取其他事务未提交的数据。
SET SESSION TRANSACTION ISOLATION LEVEL # 只是针对当前会话
READ UNCOMMITTED;
其中:
SESSION是会话。即打开一个SQL面板,然后编写SQL语句,其实就是一次会话。
关闭SQL面板,会话也就结束了。
2.案例:购票的场景
购票的场景下,如果事务之间,一如既往的相互隔离,会发生如下购票事故:
A事务看到1A坐席的状态是“未售出”,就用UPDATE语句修改了状态为“已售出”。由于没有提交事务,修改的操作只是记录在redo日志文件中,真实的数据其实没有改变。
此时,B事务启动了,他看到1A坐席是“未售出”的,于是,他用UPDATE语句修改了状态为“已售出”,且B事务很快就提交了,真实的数据文件发生了改变。
这时,A事务再去提交事务,就发现这个1A坐席被人占用了。于是就引发了回滚操作(提交不了)。虽然没有产生歧义的数据,但是动不动就购票失败,让我们很不舒服。
因此,本场景下,应该允许事务之间相互读取对方的临时状态:当事务B发现A事务的临时数据已购买了1A坐席,那么事务B就可以去购买其他的坐席,这样就不会引发数据的冲突。
3.代码演示
(1)打开2个SQL面板,代表2个事务。演示MySQL默认的事务的隔离性:
- SQL面板1:
START TRANSACTION ;
UPDATE t_emp SET sal=1; # 未提交
执行上述语句:开启事务,修改数据成功:
- SQL面板2:
START TRANSACTION ;
SELECT empno,ename,sal FROM t_emp;
执行上述语句:开启事务,查询数据成功:
SQL面板2中的工资并没有变成1块钱。这就验证了MySQL默认的事务的隔离性,相互之间不可见。
(2)更改事务的隔离级别
- SQL面板1:
START TRANSACTION ;
UPDATE t_emp SET sal=1; # 未提交
执行上述语句:开启事务,修改数据成功:
- 更改SQL面板2中事务的隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL
READ UNCOMMITTED; # 事务的隔离级别:可读取其他事务的未提交数据
START TRANSACTION ;
SELECT empno,ename,sal FROM t_emp;
COMMIT;
结果显示:工资果真因为读取到了SQL面板1中未提交的临时数据的缘故,变成了1:
4.小结
一般只适用于购票场景。
3.3 READ COMMITTED
1.语法
READ COMMITTED : 只能读取其他事务已提交的数据。
SET SESSION TRANSACTION ISOLATION LEVEL
READ COMMITTED;
2.案例:转账
3.演示
(1)SQL面板1:
START TRANSACTION ;
UPDATE t_emp SET sal=1; # 未提交
执行上述语句:开启事务,修改数据成功:
(2)SQL面板2:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; # 只能读取其他事务已提交的数据
START TRANSACTION ;
SELECT empno,ename,sal FROM t_emp;
执行上述语句:开启事务,查询数据,此时是查询不到事务A的临时数据的。所以,以下是原数据文件:
- 你提交了,就读取你已提交的数据;
- 你没提交,好吧,读取你原来数据
3.4 REPEATABLE READ
1.语法
事务在执行中反复读取数据,得到的结果是一致的,不受其他事务的影响。
SET SESSION TRANSACTION ISOLATION LEVEL
REPEATABLE READ;
默认情况下,MySQL数据库的事务的隔离级别就是这个。
2.案例
在京东商场,顾客下单后支付前,店家给商品涨价的。此时,顾客应该按照涨价前支付,还是涨价后呢?
当然是涨价前。
要求只能读取到事务开始之前的数据。
3.错误的演示:商家涨价后,顾客才下的单
SQL面板1:
START TRANSACTION ;
UPDATE t_emp SET sal=1;
COMMIT;
执行上述语句:开启事务,修改数据,提交数据成功:
SQL面板2:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; # 既然能重复读取结果一致,只能读取到事务开始之前
START TRANSACTION ;
SELECT empno,ename,sal FROM t_emp;
怎么读到了事务A 提交以后的结果?收到了其他事务的影响?
4.正确的演示:商家涨价前,顾客下单;商家涨价,顾客仍按原价支付
SQL面板1:
START TRANSACTION ; # 事务开启
UPDATE t_emp SET sal=1;
只开启事务、修改数据,不提交
SQL面板2:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION ;
SELECT empno,ename,sal FROM t_emp;
查询的是:事务A的原始数据:
SQL面板1:
COMMIT; # 提交
SQL面板2:
SELECT empno,ename,sal FROM t_emp;
重新查询下,发现:查询的仍是事务A的原始数据:
5.小结
不管事务A你提不提交,对于事务B来说,查询的都是A之前的原始数据。
错误演示跟正确演示第二步不一样吗?
因为:3.错误的演示:商家涨价后,顾客才下的单;
4.正确的演示:商家涨价前,顾客下单;商家涨价了,顾客仍按原价支付
3.5 SERIALIZABLE
前三种隔离级别只是用于某个特殊的业务场景。
序列化的隔离性,会让事务逐一执行,能够杜绝一切事务并发执行带来的问题。
原理:
前面的事务没有执行结束,后面的事务你就只能继续等着。
缺点:
因为牺牲了并发性,数据库的并发性急剧下降,很少使用。
1.语法
SET SESSION TRANSACTION ISOLATION LEVEL
SERIALIZABLE;
2.演示
- SQL面板1:
START TRANSACTION ;
UPDATE t_emp SET sal=1;
只开启事务、修改数据,不提交
- SQL面板2:
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION ;
SELECT empno,ename,sal FROM t_emp;
查询的是:迟迟没有任何数据,这是因为事务B一直在等待前一个事务A是否执行成功
- SQL面板1:
COMMIT; # 提交
- SQL面板2:
会自动显示如下结果;
注意:只有事务提交或回滚之后,才可以使用导入SQL文件命令还原数据。
四、数据的导出
4.1 数据导出与备份的区别
1.区别
区别 | 数据导出 | 数据备份 |
---|---|---|
特点 | 纯粹是业务数据文件 | 完整的MySQL的状态,既包括业务数据文件,又包括日志文件、索引文件、配置文件等 |
2.备份的分类
全量备份:最占用硬盘空间、耗时长
通常是,第一次备份是全量备份,以后都是增量备份。
比如,苹果电脑的MAC OS里,提供了一个叫做TIME MACHINE的备份程序,就是上述备份思路。同理,MySQL的备份也是。
因为MySQL的备份需要用到Linux环境,且没有图形工具可以使用,所以,这部分内容就放在以后的深入学习里。
现在,只讲数据的导出、导入。
4.2 数据导出的分类
如果业务数据不多,建议导出为SQL文档;
反之,如果业务数据很多,就导出为文本文档。
虽然导出的都是业务数据文件,但是两者包含的范围却是不同的:
对比 | SQL文档 | 文本文档 |
---|---|---|
范围 | 数据+表结构 | 只数据 |
速度 | 慢 | 快 |
五、围绕SQL文档的导出导入
5.1 导出为SQL文档:用mysqldump命令行
1.语法
其中:
2.案例演示:
切换到命令行中进行演示:
因为安装了MySQL之后,MySQL的服务注册到了Windows系统上。但是,MySQL的环境变量并没有去配置,所以,在系统命令行中使用上述指令,是找不到的。
- 配置环境变量
在电脑目录中,成功导出了SQL文档;
打开发现,就是一些数据和表结构
5.2导出为SQL文档:用图形界面
很简单。
- 先右键要导出的SQL文档
- 点击结构和数据,选择存放目录后,就导出成功了:
5.3 导入SQL文件:用命令行
上面的导出,是在系统环境下执行的;
导入的话,SOURCE
命令,只能在MySQL命令行中执行:
1.语法
SOURCE
命令用于导入SQL文件,包括常见数据表、写入记录等。
2.案例演示
成功导入了SQL文件。
5.4导入SQL文件:用图形界面
很简单,且之前经常用,此处略。
六、围绕文本文档的导出导入
因为对于文本文档来说,导出导入的命令很复杂,不容易掌握,所以这里就只使用图形界面的形式
6.1导出为文本文档:用图形界面
1.优缺点
优点:只有纯数据,因为跳出了词法分析、语法优化,所以速度非常快
缺点:如果将文本文档拿到其他的MySQL数据库是无法还原的,因为没有表结构啊。
2.案例演示
(1)先备份表结构:
(2)再导出数据,即文本文档:
成功导出了文本文档:
打开刚导出的文本文档,发现里面只有数据,如下:
6.2导入文本文档:用图形界面
先模拟在其他的MySQL数据库中没有表结构的情况:
(1)先导入表结构的SQL
在数据表上刷新,员工表的表结构就导入成功了;同时,发现里面没有任何的数据:
(2)然后再导入文本文档的数据
注意,下面要改一个参数:
数据成功导入:
刷新一下,空的表结构有新的数据了:
Comments | NOTHING