MySQL 事务(详细版)
目录
一、事务简介
1、事务的概念
2、事务执行的案例
3、对于事务的理解
二、事务操作
(一)未控制事务
(二)控制事务一
(三)控制事务二
三、事务四大特性
四、并发事务问题
五、事务隔离级别
1、事务隔离级别的介绍
2、操作事务隔离级别的语法
3、实例分析(串行化)
一、事务简介
1、事务的概念
事务是一组操作的集合,它是一个不可分割的工作单位。
当我们进行事务操作时,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
2、事务执行的案例
就比如:张三给李四转账1000块钱,张三银行账户的钱减少1000,而李四银行账户的钱要增加 1000。 这一组操作就必须在一个事务的范围内,要么都成功,要么都失败。
正常情况:转账这个操作,需要分为以下这么三步来完成,三步完成之后,张三减少1000,而李四增加1000,转账成功。
异常情况:转账这个操作,也是分为以下这么三步来完成,在执行第三步是报错了,这样就导致张三减少1000块钱,而李四的金额没变,这样就造成了数据的不一致,就出现问题了。
为了解决上述的问题,就需要通过数据的事务来完成。
我们只需要在业务逻辑执行之前开启事务,执行完毕后提交事务。如果执行过程中报错,则回滚事务,把数据恢复到事务开始之前的状态。
3、对于事务的理解
默认情况下,每一条SQL语句都是一个事务。这条SQL语句一旦执行完成,事务就会自动提交,也就是说,当执行完一条DML语句时,MySQL会立即隐式的提交事务。
事务一旦提交,表格就会有对应的变化。
如果有一件事,例如上面的转账操作,必须三个步骤同时完成才可以,此时就需要将几条SQL语句作为一个事务,保证它们同时成功或同时失败不影响原来的数据。
所以此时我们就要对事务进行控制,将几条SQL语句组合为一个事务。如果成功,就统一提交,如果失败,则避免影响数据库的内容。
二、事务操作
数据准备:
drop table if exists account;create table account(id int primary key AUTO_INCREMENT comment 'ID',name varchar(10) comment '姓名',money double(10,2) comment '余额'
) comment '账户表';
insert into account(name, money) VALUES ('张三',2000), ('李四',2000);
(一)未控制事务
1、测试正常情况
-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';
测试完毕之后检查数据的状态,可以看到数据操作前后是一致的。(总余额)
2、测试异常情况
-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- SQL语句中写中文必然报错
-- 但是在dataship中这条语句会被跳过,实际执行时,不会报错
出错了....
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';
我们把数据都恢复到2000, 然后再次一次性执行上述的SQL语句(出错了.... 这句话不符合SQL语法,执行就会报错),检查最终的数据情况,发现数据在操作前后不一致了。(总余额)
(二)控制事务一
1、查看/设置事务提交方式
-- 查看事务的提交方式
select @@autocommit ;
-- 如果赋值为1,就是自动提交事务;
-- 如果赋值为0,就是手动提交事务;
-- MySQL中默认自动提交事务,所以要设置为手动。
set @@autocommit = 0 ;
2、提交事务
-- 手动提交的情况下,要执行了commit,事务才会提交,数据库中内容才会发生改变。
commit ;
3、回滚事务
-- 执行过程中,如果发生了异常,就去执行rollback回滚,撤回该事务内已执行的操作。
rollback ;
注意事项:
① 上述的这种方式,我们是修改了事务的自动提交行为,把默认的自动提交修改为了手动提
交,此时我们执行的DML语句都不会提交,需要手动的执行commit进行提交。
② 如果业务操作正常完成,事务需要提交,就执行commit指令;如果执行事务操作的过程中出现了异常,那就执行rollback指令回滚事务,保证数据库中数据的正确性与完整性。
(三)控制事务二
1、开启事务
-- 手动开启事务,而不是修改事务的提交方式
start transaction ; 或 begin ;
2、提交事务
-- 如果事务执行成功,执行commit指令
commit ;
3、回滚事务
-- 如果事务执行失败,执行rollbakc指令
rollback ;
-- 开启事务
start transaction -- 1. 查询张三余额
select * from account where name = '张三';-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';-- 如果正常执行完毕, 则提交事务
commit;-- 如果执行过程中报错, 则回滚事务
-- 回滚事务之后就代表着当前事务已经结束了
rollback;
三、事务四大特性
1、原子性(Atomicity)
事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
2、一致性(Consistency)
事务完成时,必须使所有的数据都保持一致状态。
3、隔离性(Isolation)
数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
就如下图的上半部分,事务AB并发执行,但是不会相互影响。事务A在操作的时候,不会影响并发的事务B的执行;事务B在操作的时候,也不会影响并发的事务A的执行;它们两个是在独立的环境下运行的。
4、持久性(Durability)
事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
就如下图的下半部分,因为数据库当中的数据最后是存储在了磁盘当中的,而存储在磁盘当中的数据,就可以永久地保留下来。
四、并发事务问题
并发事务问题是事务A和事务B在同时操作某一个数据库甚至一张表时,引发的问题。
1、赃读:一个事务读到另外一个事务还没有提交的数据。
比如,在事务A执行了 select 与 update 语句后,并未提交;但是在事务B中执行 select 语句后,却查询到了事务A未提交的数据。
2、不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。
比如,在事务A两次读取同一条记录,却因为期间事务B中 id=1 的数据被更新且提交,导致读取到的数据却是不一样的。
3、幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了 "幻影"。
比如,在事务A中第一次查询,没有查询到信息;然后事务B中插入并提交了id =1的数据;此时在事务A中插入 id = 1 的数据无法插入,因为 id 是主键,id =1的数据在事务B中就已经插入;但是在事务A中再查询一次后,又无法查询得到。
五、事务隔离级别
1、事务隔离级别的介绍
为了解决并发事务所引发的问题,在数据库中引入了事务隔离级别。主要有以下几种:
Repeatable Read是MySQL的默认事务隔离级别。
事务隔离级别越高,数据越安全,但是性能越低;反之事务隔离级别越低,性能越高,但是数据越不安全。所以我们要权衡数据的安全性以及数据库的并发性能。
其中,串行化指的是再进行并发事务操作的时候,一次只允许操作一个事务。
事务A在操作的时候,只有当事务A提交完成之后,事务B才能来操作。
就比如上面幻读的例子中,如果是在串行化的情况下,因为事务A是在事务B之前执行,所以事务A执行完成之前,事务B根本无法执行下去。
事务B执行insert语句在执行后,光标会一直卡着,直到事务A执行完毕后,事务B才会执行,这样就可以避免幻读。
2、操作事务隔离级别的语法
(1)查看事务隔离级别
select @@transaction_isolation
(2)设置事务隔离级别
-- session与global二选一
-- session 是指当前设置的事务隔离级别 仅对当前对话窗口有效
-- global 是指当前设置的事务隔离级别 对所有对话窗口有效
-- 后面的四个事务隔离级别四选一即可
set { session | global } transaction isolation level { Read Uncommitted | Read committed | Repeatable Read | Serializable}
3、实例分析(串行化)
通过cmd打开两个命令行,在里面执行SQL语句,模拟两个并发事务。在下图中上面的命令行为事务A,下面的命令行为事务B。
(1)事务A还没有提交之前
事务隔离级别为Serializable (串行化) 时,一次只允许操作一个事务,所以即便事务B的insert语句被执行了,光标也会一直卡着,无法执行,直到事务A执行完毕。
(2)事务A提交之后
事务A提交后,事务B即可执行,但是此时 id = 3 的数据已经存在, 所以会报错。
以上即为MySQL 事务的全部内容,创作不易,麻烦三连支持一下呗~