数据库-事务

目录

什么是事务(事务的概念)?

事务的基本特性:

原子性:

一致性:

持久性:

隔离性:

脏读:

不可重复读:

幻读:

隔离级别:


在开始介绍事务之前,我们先来假设一个场景:

有一个账户余额表

   idbalance(余额)
11000
2500

转账操作:

1 给 2转账500

①首先我们得给1的账户余额减去500

    update 账户余额表 set balance = balance - 500 where id = 1;

②给2的账户余额加上500

    update 账户余额表 set balance = balance + 500 where id = 2;

试想一下,比如程序执行第一个操作之后,第二个程序执行之前,出现了严重的问题(程序崩溃,主机断电......),就会使数据库的内容,就会出错。比如,执行完操作①之后,给用户1减了500,但是没有执行操作②,那不就出事了嘛,所以这时候就需要使用事务来解决

什么是事务(事务的概念)?

所谓事务,就是相当于把要执行的SQL,打包成一个“整体”,这个“整体”在执行过程中就能够做到,要么整个都执行完,要么就一个都不执行,就可以避免出现上述转账一半的中间状态

此处的“一个都不执行”不是这些SQL真的没执行,而是执行一半,发现出错的时候,数据库会自动进行“还原操作”,相当于把前面执行过的SQL给“撤销”,最终的效果看起来就像是没执行一样,这样的机制,就称为“回滚”(rollback),同时也把事务支持的上述特性称为“原子性”

问:那么数据库是如何知道,具体是怎样回滚的呢?如何知道前面的sql做出了什么的修改呢?

答:在数据库内存在一系列的“日志体系”,记录到文件中去,这样既可以应对“程序崩溃”也可以应对“主机断电”(虽然断电了,但是回滚的日志还是存在的,此时下次主机上电,下次数据库启动的时候就可以根据回滚日志的内容,来进行回滚操作)

那么如何开启事务呢?

(1)开启事务:start transaction;

(2)执行多条SQL语句

(3)回滚或提交:rollback/commit;

说明:rollback即是全部失败,commit即是全部成功。

根据业务逻辑决定是使用commit;提交事务,使所有修改生效,还是使用rollback;撤销事务中的一切操作,回滚到事务开始前的状态。

事务的基本特性:

原子性

指事务里的所有操作必须一起成功,或者一起失败,不能只完成其中一部分

用大白话解释:当我们炒一盘菜的时候,从洗菜、切菜到炒熟装盘,这一系列动作必须连续完成,中间不能停下。原子性就像是保证了,要么这盘菜从头到尾顺利炒好端上桌,要么因为某个原因(比如火突然灭了),菜根本没炒还在准备阶段。你不会吃到一半炒好的,一半没有炒的菜

一致性:

一致性保证在事务执行前后,数据库都保持合法的状态,即符合所有的数据完整性规则(如实体完整性、参照完整性和用户定义的完整性)。事务必须把数据库从一种一致状态转换到另一种一致状态。

用大白话解释:就像拼图游戏,每一块小图片都得放到正确的位置上,才能最终组成完整的画面。如果有一块放错位置,或者缺了一块,那拼图就不完整,看起来就不对

放到数据库里,一致性就是说,无论数据怎么增删改查,数据库里的信息都要保持正确的状态,遵循预先设定好的规则,比如账户余额不能无缘无故变多或变少,订单的状态变化要合理。这样一来,任何时候查看数据,它们都应该是一致的、合理的,不会出现违背逻辑的情况。

持久性:

持久性就是确保你的数据一旦正确保存了,即便电脑关机、网络出问题,甚至系统崩溃,那些重要信息还能安然无恙地待在那里,下次打开时依旧能看到。

用大白话解释:就像在沙滩上画画和在石头上刻字的区别。想象一下,你在沙滩上画了一个美丽的图案,但海浪一来,作品就被冲刷掉了,不留痕迹。而当你在一块石头上刻下了同样的图案,不论风吹雨大,甚至时间流逝,那个图案依然清晰可见。

隔离性

在多用户环境下,当多个事务并发执行时,隔离性确保每个事务好像在独立地、不受其他事务影响的情况下执行,即使实际上这些事务是在同一时间处理的。

具体来说,隔离性要解决的是并发控制问题,防止由于事务之间的不当交互而引发的数据不一致和错误结果。例如,如果没有适当的隔离,一个事务可能读到另一个事务尚未提交(可能还会被回滚)的数据(脏读),或者在两次相同的查询中得到不同的结果(不可重复读),亦或是发现突然出现了之前不存在的记录(幻读)。

那么上述所说的脏读,不可重复读和幻读是什么呢?请看下文: 

脏读:

想象一下,如果你正在读一本小说,但这本书还在作者草稿阶段,里面有些章节可能还未定稿,甚至可能有错别字或情节未完善。如果你在这个时候读了这本书,得到了一些信息,而过后作者决定修改这些内容,当你再次去读的时候,发现之前读到的内容变了,甚至某些段落被完全删除了

在数据库中,脏读就是指一个事务读到了另一个事务已经修改但还未提交的数据。如果那个修改事务后来因为某些原因被回滚了,那么你之前读到的数据就像是从未存在过一样,成了“脏数据”,这就是脏读。为了避免这种情况,数据库提供了不同的事务隔离级别,比如“读已提交”级别就可以防止脏读的发生。(后文会讲)

不可重复读:

当你连续两天去超市买同一种零食。第一天,你发现货架上有一种新口味的薯片,决定第二天再来买。但当你第二天满怀期待地回到超市,原本的新口味薯片已经被另一种新上架的产品替代了。虽然你找的是同一个位置的“同款”零食,但因为超市货物快速更新,你再也找不到昨天的那种薯片了。

放到数据库的概念里,不可重复读就像是你在数据库里查询某条信息,过一会儿再查一次,却发现因为其他操作,数据已经被改了,就像超市的零食被新货取代一样。不可重复读是指一个事务读到了另一个事务已经修改并且已经提交的数据。在数据库中,“可重复读”(Repeatable Read) 隔离级别可以解决不可重复读的问题。

幻读:

当你去超市买水果,第一次走到苹果区看了看,那时候货架上摆着红富士,金冠苹果等,你没看到你喜欢的青苹果,就先去买了别的东西。可就在这个空档,超市员工补货上架,新添了青苹果,等你拎着东西回来,再想看看有没有青苹果时,嘿,这时候青苹果就这么“神奇”地出现在架子上,好像你第一次来时完全没注意到一样

放到数据库的场景下,就好比你第一次查询所有完成的任务列表,显示了任务1到任务5。之后,别人迅速完成了一个新任务并录入系统,变成了任务6。当你再次查询时,发现列表里多了个任务6,感觉像是它突然“凭空”出现,这就是所谓的“幻读”情况。“串行化”隔离级别可以解决幻读问题

隔离级别:

在mysql中,提供了四个隔离级别,可以通过配置文件来设置当前服务器的隔离级别是哪个级别,设置不同的隔离级别,就会使事务之间的并发执行的影响产生不同的差别。

1) 读未提交(Read Uncommitted)

这种情况下,一个事务读取另一个事务未提交的数据,此时,就可能会产生脏读,不可重复读,幻读三种问题,但是此时,多个事务并发执行程度是最高的,执行速度也是最快的

2)读已提交(Read Committed)

这种情况下,一个事务只能读取另一个事务提交之后的数据(给写操作加锁了),此时,可能会产生不可重复读,幻读问题 (脏读问题解决了),此时,并发程度会降低,执行速度会变慢,同时也称为,事务之间的隔离性提高了

3)可重复读(Repeatable Read)

这个情况下,相当于给写操作 和 读操作都加锁了,此时,可能会产生幻读问题,解决了脏读和不可重复读的问题,并发程度进一步降低,执行速度进一步变慢,事务之间的隔离性进一步提高了

4)  串行化(Serializable)

此时,所有的事务都是在服务器上一个接一个的执行的,此时,脏读,不可重复读,幻读问题全部解决了,但代价是大大降低了并发性能,速度也变得最慢了

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值