8.7 MySQL数据库的事务机制、数据导入导出


目录

[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.语法

其中:

  • -p表示要手动输入密码
  • dump------like pour

2.案例演示:

切换到命令行中进行演示:

  • 进入到MySQL在C盘的安装目录中:

    这里面包含很多命令,包括用于导出SQL文档的mysqldump命令

因为安装了MySQL之后,MySQL的服务注册到了Windows系统上。但是,MySQL的环境变量并没有去配置,所以,在系统命令行中使用上述指令,是找不到的。

  • 配置环境变量

  • 切换到Windows的命令行中:

    用mysqldump命令,导出SQL文档

在电脑目录中,成功导出了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)然后再导入文本文档的数据

注意,下面要改一个参数:

数据成功导入:

刷新一下,空的表结构有新的数据了:

七、总结

声明:Jerry's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 8.7 MySQL数据库的事务机制、数据导入导出


Follow excellence, and success will chase you.