最近在复习mysql,复习到了mysql事物处理(TransAction),帮自己回顾一下,如果你也想了解什么是mysql的事物处理,希望这篇文章会对你有帮助!!!正文开始:
目录
一、事物的概念
🤷♀️什么是事物?
事务指逻辑上的一组操作,组成这组操作的各个单元,通俗来说,要么全部成功,要么全部失败。
事务就是由单独单元的一个或多个sql语句组成,在这个单元中,每个sql语句都是相互依赖的。
在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。
就是说如果单元中某条sql语句一旦执行失败或者产生错误,那么整个单元将会回滚(返回最初状态)。所有受到影响的数据将返回到事务开始之前的状态,但是如果单元中的所有sql语句都执行成功的话,那么该事务也就被顺利执行。
二、为什么使用事物?
首先准备一个测试表:
drop table if exists accout;
create table accout(
id int primary key auto_increment,
name varchar(20) comment '账户名称',
money decimal(11,2) comment '金额'
);
insert into accout(name, money) values
('阿里巴巴', 5000),
('四十大盗', 1000);
比如说,四十大盗把从阿里巴巴的账户上偷盗了2000元
-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';
假如在执行以上第一句SQL时,出现网络错误,或是数据库挂掉了,阿里巴巴的账户会减少2000,但是四十大盗的账户上就没有了增加的金额。
🤷♂️2.1 那么应该怎么解决呢?
事物就是为了解决上述问题~~
事物的本质就是把多个sql语句给打包成一个整体,要么全部执行成功,要么就一个都不执行;
而不会出现”执行一半“这样的中间状态!!!
🥰一个整体就是所谓的原子性(atom)认为是事物能够分割的最小单位~~
不是真的没执行,而是”看起来好像没执行一样“
执行了,执行一半出错了,出错之后,选择了恢复现场,把数据还原成未执行之前的状态了~~
这个恢复数据的操作,称为”回滚“(rollback)
如果把上述俩个操作作为一个事物,当第一个sql执行完之后,数据库崩溃;
当下次数据重新启动完成之后,就会自动的把上次修改一半的数据给进行还原~~
此处是需要额外的部分来记录事物中的操作步骤,进行回滚的时候,数据库里面有个专门来记录事物的日志;
正因为如此,使用事物的时候,执行sql的开销是更大的,效率是更低!!!
三、事物的四个特性(八股文)
- 原子性(Atomicity):指事务是一个不可分割的最小工作单位,事务中的操作只有都发生和都不发生两种情况。(最核心的特性)
- 一致性(Consistency):事务必须使数据库从一个一致状态变换到另外一个一致状态。数据要靠谱!!
- 持久性(Durability):一个事务一旦提交成功,它对数据库中数据的改变将是永久性的,内容是写在硬盘上的,接下来的其他操作或故障不应对其有任何影响。
- 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
事物的隔离性,存在的意义就是为了在 数据库并发处理事物的时候不会有问题!!
四、事物的使用步骤
😉(1)开启事务:start transaction;
😮(2)执行多条SQL语句
🤐(3)回滚或提交:rollback/commit;
说明:rollback即是全部失败,commit即是全部成功。
假设数据库中已经有表存在:
#步骤一:开启事务(可选)
start transaction;
#步骤二:编写事务中的sql语句(insert、update、delete)
#这里实现一下"李二给王五转账"的事务过程
update t_account set balance = 50 where vname = "李二";
update t_account set balance = 130 where vname = "王五";
#步骤三:结束事务
commit; #提交事务
# rollback; #回滚事务:就是事务不执行,回滚到事务执行前的状态
运行结果:
五、并发执行事物可能产生的问题
🎆5.1 脏读问题
假设老师在写代码,在写代码的过程中,有一个同学,在老师身后经过;偷偷的瞄了一眼屏幕,看到了代码中的一些内容,然后他就走了;
🤦♀️那么很可能,他走了之后,老师的代码,又改了!!
此时读操作就称作为"脏读”,读到的数据也称为“脏数据”,脏的意思, 是“无效”,而不是“埋汰”~~
为了解决脏读问题,mysql引入“写操作加锁”这样的机制,老师和同学们约定好,写操作的过程中,同学不许来看,等老师改完,提交到码云上,再通过码云来看!!
写的过程不能看(给写操作加锁),写完了才能看!!
这就意味着,同学的“读操作”和老师的“写操作”不能并发了~~
这个写操作加锁,就降低了并发程度(降低了效率),提高了隔离性(提高了数据的准确性)
🎶5.2 不可重复读
还是老师写代码,同学想看;于是就约定好,写的时候不许看,等提交了再一起看~~
于是老师提交了版本1,此时就有同学来读这个代码了~~
于是老师又打开代码,继续修改代码,然后又提交版本2~~
😢同学在开始读的过程中,读到的是版本1的代码,读着读着,老师提交了版本2,此时这个同学读的代码,刷的一下就变样了!!
这个问题就叫“不可重复读”~~
事务1已经提交了数据.此时事务2开始去读取数据.在读取过程中,事务3又提交了新的数据.
此时意味着同一个事务2之内,多次读数据,读出来的结果是不相同的~~(预期是一个事务中,多次读取结果得一样)就叫做“不可重复读”
刚才的约定是,修改的时候,同学不要读,是给写加锁;
现在约定同学读的时候,老师不能修改,就是给读加锁!!
这个读加锁,又进一步的降低了事物的并发处理能力(处理交流也降低),提高了事物的隔离性(数据的准确性又提高了)
🎇5.3幻读
当前已经约定了读加锁和写加锁,解决了不可重复读和脏读问题.
由于约定了读加锁,同学读的时候,老师不能改代码了~~老师在这干的等着??光摸鱼不干活~~有点难受~~
🤦♂️所以老师想了办法~~同学读Student.java,那好,我就创建一个Teacher.java,就写这个代码呗~~
这样的情况,大多数情况下都没事,少数情况下,个别同学发现了,读代码读着突然冒出个Teacher.java,有的同学就觉得接收不了了~~
在读加锁和写加锁的前提下,一个事务两次读取同一个数据,发现读取的数据值是一样的,但是结果集不一样~~
(Student.java代码内容不变,但是第一次看到的是只有Studentjava这个文件,第二次看到的是Studentjava和Teacher.java 了...)
这种就称为"幻读"
数据库使用“串行化”这样的方式来解决幻读,彻底放弃并发处理事物,一个接一个的串行的处理事物,这样做,并发程度是最低的(效率是最慢的),隔离性是最高的(准确性也是最高的)!!
六、事物的隔离级别
mysql中的四种事务隔离级别如下:
🙂1. read uncommitted(读未提交数据):允许事务读取未被其他事务提交的变更。(脏读、不可重复读和幻读的问题都会出现)。
🆒2. read committed(读已提交数据):只允许事务读取已经被其他事务提交的变更。(可以避免脏读,但不可重复读和幻读的问题仍然可能出现)
😶🌫️3.repeatable read(可重复读):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新(update)。(可以避免脏读和不可重复读,但幻读仍然存在)
😎4. serializable(串行化):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可避免,但性能十分低下(因为你不完成就都不可以弄,效率太低)
一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性就越差。
#设置当前mysql连接的隔离级别:
set session transaction isolation level read uncommitted;
#设置数据库系统的全局的隔离级别:
set global transaction isolation level read uncommitted;