1、mysql事务
—mysql中,事务其实是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性,例如:银行存款:
a - > -100
>update user set money = money -100 where name ="a";
b - > +100
>update user set money = money +100 where name ="b";
—实际程序中,如果一条语句执行成功了,而另一条语句执行失败,那么麻烦就大了……
>update user set money = money -100 where name ="a";
>update user set money = money +100 where name ="b";
多条sql语句有要求要么就同时成功,要么就同时失败
2、mysql中如何控制事务?
——查看事务状态(开启还是关闭)
>select @@autocommit;
上图‘1’表示mysql 默认是开启事务的(自动提交)
——默认事务开启是什么?
当我们在执行sql语句时,效果会立即体现出来,且不能回滚(回滚后面会讲到)
——下面用一个案例来解释mysql事务:
(1)创建新的数据库名为bank
>create database bank;
(2)在bank数据库中创建新的表名为user
> create table user(
-> id int primary key,
-> name varchar(20),
-> money int);
(3)往user表中添加数据
> insert into user values(1,'a',1000);
(4)查看是否添加成功
>select * from user;
(5)回滚(就是撤销sql语句执行的效果)
>rollback;
(6)验证sql的语句执行的效果是否撤销
>select * from user;
(7)如果想要让回滚有效的话需要关闭事务(关闭mysql的自动提交)
>set @@autocommit=0;
>select @@autocommit;
验证回滚:
>insert into user values(2,'b',1000);
查看此时的user表
>select * from user;
【注】上述的表其实是虚拟的如果现在回滚就可以实现撤销
>rollback;
>select * from user;
>commit;
【总结】
事务:
——自动提交:@@autocommit=1;
——手动提交:commit;
——回滚:rollback;
转账:
>update user set money = money -100 where name ="a";
>update user set money = money +100 where name ="b";
如果转账失败(同时失败)
可以用回滚实现撤销
>rollback;
——实现:
(8)小结
——手动开启一个事务的方式:(在这里说一下不知道是不是版本的问题我的电脑上试过了 <2>begin;与 <3>start transaction;是改不了的建议使用第一个,如果您跟我一样,后边关于设置手动事务的都用第一个方法)
<1>set @@autocommit =0;
<2>begin;
<3>start transaction;
具体验证可以参照(7)的流程哦
——关闭手动开启恢复自动开启
>set @@autocommit =1;
——查看事务的状态
>select @@autocommit;
——回滚
>rollback;
——提交
>commit;
【总结】
综上:我们学到了,事务是以两种方式存在的:一是手动开启事务,二是默认(自动)开启事务
手动开启事务给我们提供了一个修改的机会,如果操作失败的话可以通过回滚,实现修改,如果操作成功可以手动提交(commit)增加数据的安全性哦
3、事务的四大特征
A 原子性:事务是最小的单位,不可以再进行分割了
C 一致性:事务要求同一事务中的sql语句,必须保证同时成功或者同时失败
I 隔离性:事务1与事务2之间具有隔离性(后面详解)
D 持久性:事务一旦结束(commit),就不可以返回(rollback)
4、事务的隔离性
(1)read uncommitted 读未提交的
(2)read committed 读已提交的
(3)repeatable read 可以重复读
(4)serializable 串行化
(1)read uncommitted 读未提交的
【定义】现有事务a和事务b,a事务对数据进行操作,在操作过程中,事务没有被提交,但是b可以看见a操作的结果
>insert into user values(3,'小明',1000);
>insert into user values(4,'淘宝店',1000);
【拓展】
——如何查看数据库的隔离级别
mysql 8.0
> select @@global.transaction_isolation;(如下图:mysql默认的系统隔离级别)
会话级别的
> select @@transaction_isolation;
mysql 5.x
> select @@global.tx_isolation;
会话级别的
> select @@tx_isolation;
——如何修改数据库的隔离级别?
>set global transaction isolation level read uncommitted;
查看修改结果:
模拟脏读:上述已经添加了小明和淘宝店两个用户
小明现要在淘宝买一双800元的鞋子,开始付钱
小明 ——>成都
淘宝 ——>广州
>set autocmmit =0;
转账
>update user set money = money -800 where name ='小明';
>update user set money = money +800 where name ='淘宝店';
【总结】在事务隔离性为 read uncommitted ( 读未提交的)情况下:
两个不同的地方,都在进行操作,如果事务a开启之后,他的数据可以被其他事务读取到
这样就会像上述实例那样,出现脏读;
脏读:一个事务读到了另外一个事务并没有提交的数据,这就叫做脏读
当然实际开发中是不允许的
(2)read committed 读已提交的
——修改事务隔离性
>set global transaction isolation level read committed;
实例:bank数据库,user表
>begin;
> select * from user;
小张出去上厕所去了,这时小王又在另一台电脑上开了一个账户
> insert into user values(5,'c',100);
>select avg(money) from user;
【总结】在事务隔离性为 read committed (读已提交的)
虽然可以读到另外一个数据提交的数据(不会出现脏读),但还是会出现问题就是
读取同一个表,发现前后数据不一致,
不可重复读现象: read committed
(3)repeatable read 可以重复读
先对之前的隔离性做更改
>set global transaction isolation level repeatable read;
——那么在这种情况下又会发生什么事情呢?
【实例】
张全蛋—北京(是repeatable read 事务隔离的情况下)
>set autocommit =0;
开通一个账户
>insert into user values(6,'d',1000);
>select * from user;
王尼玛—上海(默认事务隔离性的情况下)
>set autocommit =0;
也想开通账户,开通前先查看(注意模拟的话可以再打开一个终端)
>select * from user;
> insert into user values(6,'d',1000);
结果:
>insert into user values(7,'d',100);
>select * from user;
【总结】这种现象叫做幻读
幻读:事务a和事务b同时操作一样表,事务a提交数据也不会被事务b读到,就会造成幻读
(4)serializable 串行化
——先更改事务隔离性
>set global transaction isolation level serializable;
【实例】
——张全蛋—成都
>set autocommit =0;
开户并提交
>insert into user values(7,'赵铁柱',1000);
>commit;
——王尼玛—北京
>set autocommit =0;
查看表,看到了赵铁柱
>select * from user;
——张全蛋—成都
又开了一个户
>insert into user values(8,'王小花',1000);
但是进入等待状态了,卡住了
这时——王尼玛—北京上述有说到正在看表,此时马上提交:commit,张全蛋那立刻就不卡了
这就是串行化
【总结】
当user表被另外一个事务操作的时候,其他事务里面的写操作,是不可以进行的
进入排队状态(串行化),直到王尼玛不进行事务操作了(输入commit结束事务之后),张全蛋这个写入操作才会执行(在没有超时的情况下)
——串行化带来的问题:性能太差
read uncommitted > read committed > repeatable read > serializable
即隔离级别越高,性能越差
mysql默认的级别是 repeatable read
关注个人公众号,有福利哦……