MySQL数据库的事务

时间:2022-11-28 14:55:32

MySQL数据库的事务

一、事务是什么?

数据库的事务是一种机制,一个操作序列,里面包含了一组数组库操作命令
事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数组库命令要么同时成功,要么同时失败
事务是一个不可分割的工作逻辑单元
MySQL数据库的事务
比如小张向小王借500块钱,这个一系列操作就可以当作一个事务,我们可以分为两个操作,1是小张的账户 -500,2是小王的账户+500,但是如果要是我们的数据库出现异常了,小张的账户-500了,但是小王的账户没有+500,那么这个操作就十分危险了。那么这个时候事务的作用就体现出来了。
MySQL数据库的事务
这里我们就可以防止错误的发生了,当出现异常时,我们就可以回滚事务。
开启事务:

-- 开启事务
START TRANSACTION;
--或者
BEGIN;

提交事务:

-- 提交事务
COMMIT;

回滚事务:

ROLLBACK;

我们创建一个账户表

CREATE TABLE account(
   id int primary key auto_increment,
	 name varchar(50),
	 money double(10,2)
);
-- 初始小张和小王账户信息
INSERT into account(name,money) values('小张',1000),('小王',1000);

MySQL数据库的事务

转账操作

-- 1. 小张金额 -500
UPDATE account set money = money - 500 where name = '小张';

-- 2. 小王金额 +500
UPDATE account set money = money + 500 where name = '小张';

MySQL数据库的事务
我们可以发现这是正常情况下,符合我们预期,但是我们的程序要是出现了异常情况。
MySQL数据库的事务

我们举一个很简单的异常情况,我们想写注解但是没加-- 程序发生了异常。
MySQL数据库的事务
我们发现了小张的账户 -了500 ,但是小王并没有+500,这种事要是发生在银行就是重大失误。
这时候我们就可以发挥事务的作用了。
MySQL数据库的事务
我们发现在当前的用户查询可以发现账户发生了变化,但是我们开启了事务之后在commit之前只是临时的操作。
MySQL数据库的事务
我们切换了个用户去查询发现并未改变。
但我们发现发生异常之后,我们需要恢复到事务之前的状态,这时我们需要进行回滚操作。
MySQL数据库的事务
MySQL数据库的事务
我们再去当前用户查看账户信息,发现账户回到了开始的状态。

START TRANSACTION;
-- 1. 小张金额 -500
UPDATE account set money = money - 500 where name = '小张';
-- 2. 小王金额 +500
UPDATE account set money = money + 500 where name = '小王';
-- 提交事务
commit;

当我们执行完事务之后发现是预期的效果,那么我们就可以提交事务,当我们提交完事务之后,数据就真真实实的在硬盘上改变了。
MySQL数据库的事务
这是我们在其他用户去查询发现真真实实的改变了,上面我们基本的感受了一下事务的用法和作用。
有了这个我们是否就不担心删库删表了呢?
我们回滚ROLLBACK的操作,实际是我们把事务之前的操作逆着回去,前面插入,我们删除等,数据库会把事务执行的操作记录下来。
这些操作是有很大开销的,可以保存,但不能够无限保存。当我们回滚时,数据库要是右几十亿条数据,占据了几百G硬盘空间,你不可能花费空间将其全部记录下来。

二、事务的四大特征

原子性

原子性(Atomicity): 事务是不可分割的最小操作单元,要么同时成功,要么同时失败

事务的原子性,也是事务的核心特性,也是事务存在的必要。

一致性

一致性(Consistency): 事务完成时,必须所有的事务都保持一致状态

一致性证明我们事务前后的数据都是合法合理的,比如小张和小王事务前账户总额是2000,事务后账户总额也得是2000,事务后账户总额不能是1500,也不能是2500.

持久性

持久性(Durability): 事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

事务在执行的时候,会把执行的过程记录在硬盘上,即使我们执行到一半电脑关机了,等到下次开机后,也会根据上次的记录进行回滚到初始状态,因为关机也算是事务的一种异常情况。

那我们很容易可以想到,我们日常写sql时,都会写入到硬盘,那这是否和事务有关系呢?

我们日常书写的sql相当于是事务,而且MySQL的事务是默认提交的。

-- 查看事务的默认提交方法
select @@autocommit;
-- 1. 自动提交 0. 手动提交

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QDsowpVI-1669596945986)(C:\Users\86187\AppData\Roaming\Typora\typora-user-images\image-20221127175900722.png)]

这些我们就可以理解为啥我们sql都是直接写入硬盘的了。当我们不想直接写入硬盘时,而是手动提交时,我们可以自己修改事务的提交方法。

-- 修改事务的提交方式为手动
set @@autocommit = 0;

隔离性

隔离性(Isolation): 多个事务之间,操作的可见性

说简单点,就是一个数据库服务器,可能同时执行多个事务时,事务之间的影响程度

如果隔离性越高,就意味着事物之间的并发程度越低,执行效率越慢,但是数据准确性越高。

如果隔离性越低,就意味着事物之间的并发程度越高,执行效率越快,但是数据准确性越低。

在这里我们无法说该怎么选择,只能说根据具体的实际情况去选择隔离性的高低,有的情况下需要高的准确性(银行,高科技),有些东西追求快(游戏,延迟低一点,血量5000的话有个10几的误差大差不差的)。

脏读

有一天,我正在宿舍写作业,我舍友看到了我前四个选择题是ABCD,这时候我在写作业是事务A,舍友看我的作业是事务B,读写都是针对同一份数据,当他走了时候,我发现自己写错了,改成了DCBA。

这种舍友看到我错误答案的情况,就是脏读问题,“读脏数据(dirty data)”,想要解决这种脏读情况,就是提高隔离性,降低并发,给"写操作加锁".

不可重复读

当我加了写加锁时(具体就是我写的时候,舍友不能看,等我写完了之后再给他看),当我给舍友把在线文档发过去的时候,舍友正在读的时候,我又觉得有一个题有问题去修改了一下在线文档,导致舍友正在看的时候在线文档突然变了,这个问题就是不可重复读,简单地说就是一个事务,两次去读同一个事务,结果不一样。

我们想解决这个问题,那么就是当舍友在读的时候,我不能再修改了。事务A与事务B的隔离性又提高了,速度变慢了(因为我得等舍友读完了才能去改),准确性提高。

幻读

这时候读写锁和写加锁都约定了,虽然我不能去改那个在线文档,但是我还可以在发送一个在线文档,或者撤回发的那个在线文档,虽然舍友读的哪一个在线文档没有变化,但总在线文档数变化了,这个问题称为幻读问题,同一个事务中,两次读到的结果集合不一样。

解决幻读的问题,严格串行化,彻底舍弃并发。

MySQL的四个隔离级别

1.read uncommited

不做任何限制,支持多事务之间的并发。并发程度最高,隔离性最差。 会产生脏读 + 不可重复读 + 幻读

2.read commited

写加锁,隔离性提高,并发程度降低。 解决了脏读问题, 仍然存在不可重复读 + 幻读问题

3.repeatable read

写加锁,读加锁,隔离性再次提高,并发程度再次降低。 解决了脏读 + 不可重复读问题 , 仍然存在幻读问题。

这个隔离级别也是MySQL的默认隔离级别,如果没有特殊的业务需要,不建议去修改这个隔离级别。如果需要改的话,通过MySQL的配置文件来进行调整。

4.serializable

严格执行串行化,并发降到最低。 解决了 脏读 + 不可重复读 + 幻读问题。