MySQL 事务

为什么要用到事务

我们所有的程序都是按顺序来执行代码,但是就会存在中途出现异常,甚至代码挂掉无法执行后续的代码,这是很常见的。可是有的情况下我们容不得程序中途挂掉,就比如银行汇款,如果a账户给b账户汇款,a中余额1000元,b中余额1000元,当a给b汇款500元时,首先a要从余额中扣除500元,b要从余额中加上500元,在不出错的情况下,程序执行结束,a余额500元,b余额1500元。但是,当中途程序出错,数据库中途挂掉,a扣了500之后,b的500并没有加上去吗,这个时候就很尴尬了…我们宁愿程序出错a的余额没有扣除都是好的,最起码没有金钱的损失。为了解决以上问题,我们就会用到事务,就是为了解决SQL语句要么全部执行成功,要么全部执行失败。

事物的概念

事物指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。
简单来说,就是把若干个SQL语句打包成一个“整体”,要么都不执行,要么都执行完毕但是这里的“都不执行”不是这些SQL真的没有执行,而是执行一半,发现出错的时候,数据库会自动进行“还原操作”,相当于把之前执行过的SQL给撤销,最终看起来像是一个都没有执行的效果。这样的机制我们称为“回滚(rollback),同时也把事务支持的上述”特性“称为”原子性“。

日志体系

数据库是怎么进行回滚的?如何知道前面的SQL做出了啥样的修改呢?
数据库中存在一系列的”日志体系“,当开启事务的时候,此时每一步执行的SQL都对数据进行了哪些修改,这些信息就会记录在案。后续如果需要回滚,就可以参考之前记录的内容,进行还原。并且以文件的方式记录和存储,这样即可以应对”程序崩溃“也能应对”主机掉电“的情况。

事务的使用

(1)开启事务
start transaction
(2)执行多条语句
(3)回滚或提交
rollback/commit
说明:rollback是全部失败,commit是全部成功
例如:

-- salary_id 为1的 给 salary_id 为2的转100
start transaction;
update salary set salary = salary - 100 where salary_id = 1;
update salary set salary = salary + 100 where salary_id = 2;
commit;

程序运行之前
在这里插入图片描述
程序运行之后
在这里插入图片描述

事务的基本特性(重点掌握)

事务涉及到的四个核心特性:
1.原子性(最重要的特性):就是上文的回滚机制
2.一致性:描述的是,事务执行前和执行后,数据库中的数据,都是“合法状态”,不会出现非法的零时结果的状态。
3.持久性:事务执行完毕之后,就会修改硬盘上的数据,事务都会持久生效。
4.隔离性(非常复杂的一个性质):描述了多个事务并发执行的时候,互相之间产生的影响是怎样的。

隔离性

1)脏读
2)不可重复读
3)幻读

  • 脏读
    两个事务A和B并发进行,其中事务A在针对某个表的数据进行修改,A执行过程中,B也去读取数据,当B读完之后,由于A的修改操作有误,回滚至修改之前,导致B读到的数据不是”正确“的数据,而是读到了零时的”脏数据“
时间顺序转账事务取款事务
1开始事务
2开始事务
3查询账户余额为2000元
4取款1000元,余额被更改为1000元
5查询余额为1000元(产生脏读数据)
6取款操作发生错误,事务回滚,余额变为2000元
7转入2000元,余额更改为3000元(脏读的1000+2000)
8提交事务
备注按照正确的逻辑,此时账户余额应为4000元

结论:读取了为提交的数据!
解决方法:修改时,不能读(给写操作加锁!

  • 不可重复读
    不可重复读指在数据库访问时,一个事务在前后两次相同的访问中却读到了不同的数据内容。
    比如说事务A的执行周期较长,事务A在第一次读取某个数据时,此数据的值为100,读取完成后,事务A又去执行其他的事情,在这个过程中,事务B将这个数据的值修改为200,然后事务A做完其他的事情后,又来读取这个数据的值,发现这个值和第一次所读取的值不相同,这种现象称为不可重复读。
时间顺序事务A事务B
1开始事务
2第一次查询小明年龄为21岁
3开始事务
4其他操作
5更改小明年龄为22岁
6提交事务
7第二次查询小明年龄为22岁
备注按照正确的逻辑,事务A前后两次读的数据应该保持一致

结论:前后多次读取,数据内容不一致!
解决方法:读取时,其他事物不能修改(给读操作加锁!

  • 幻读
    幻读指的是事务A在查询完记录总数之后,事务B执行了新增操作,事务A再次查询记录总数,发现两次查询的结果不一致,平白无故的多出了几行数据。
时间顺序事务A事务B
1开始事务
2第一次查询,数据总量100条
3开始事务
4其他操作
5新增100条数据
6提交事务
7第二次查询,数据总量为200条
备注按照正确的逻辑,事务A前后两次读的数据总量应该保持一致

解决方法:进行“串行化”,一次只执行一个事务。

那么脏读、不可重复读和幻读又和隔离性有什么关系呢?
在MySQL中提供了四个隔离级别,可以通过配置文件来设置当前的服务器隔离级别时哪个级别。
1)read uncommitted 读未提交
这种情况下,一个事务可以读取另一个事务未提交的数据,此时就可能会产生脏读、不可重复读和幻读三种问题,但是此时多个事务并发程度是最高的,执行速度也是最快的。
2)read committed 读已提交
这种情况下,一个事务只能读取另一个事务提交之后的数据(给写操作加了锁)此时,可能会产生不可重复读和幻读问题(脏读问题解决了)此时并发成都降低,执行速度会变慢,同时事务之间的隔离性提高了,事物之间的相互影响变小了,得到的数据更准确了。
3)repeatable read 可重复读
这是MySQL默认的隔离级别,这个情况下,相当于是给写操作和读操作都加了锁,此时可能产生幻读问题,解决了脏读和不可重复读问题,并发程度进一步降低,执行速度进一步变慢,事务直接按的隔离性进一步提高了。
4)serializable 串行化
此时,所有的事务都是在服务器上一个接着一个的执行的,此时解决了脏读、不可重复读和幻读问题,并发程度最低,执行速度最慢,隔离性最高,数据最准确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值