SQL之事务

什么是事务#

在数据库中,我们将一条SQL语句称为一次基本的操作。将若干条SQL语句“打包”在一起,共同执行一个完整的任务,这就是事务。
事务(Transaction)由一次或者多次基本操作构成,或者说,事务由一条或者多条 SQL 语句构成。
reference: https://zhuanlan.zhihu.com/p/605751518

事务总是针对于多并发来说的,因为只有一个客户端或一个线程的情况下,对于数据库的操作都是线性的(如果不搞些骚操作的话),这时候的每一个SQL语句都是按照顺序执行的,也就无所谓事务不事务的了。
但是在多并发的场景下就大大不同了,假设这样的场景:你在一张表中存了一些种子链接,正欲找出来做一番学术研究,正好你的朋友也在操作这张表,一不小心把表清空了,你喝着可乐唱着歌,突然就找不到资源了,这可太难受了。

这就需要一种机制来保证不会出现这种情况。事务的概念正是为了正义的资源不被邪恶篡改而提出的(bushi

众所周知,事务具有以下4个属性,并称ACID:

  • 原子性,一个事务中的操作要么全部成功,要么全部失败。
  • 一致性,在一个事务的开始前和结束后,数据库中数据的完整性不能被破坏,即要存储的数据的预设规则必须满足,不能被破坏了。说人话就是我表中存了车牌号和链接,要求都不能是空的,开始每条记录都是完整非空的,你不能事务操作完,车牌号还在,链接给我变成空了。
  • 隔离性,数据库允许多个事务可以同时对数据进行读写和修改,每个事务都会认为只有自己在操作数据库,其他事务对他来说是透明的。
  • 持久性,事务在结束后,如果成功执行,那么对数据库中的数据的操作是永久的,就算之后电脑死机、程序挂掉都不会影响这些数据,也不会丢失。

存在的问题#

需要明确的是,事务出现的问题都是事务与事务之间的,单个事务就好像只有一个线程的程序,顺序执行不会有任何问题。

脏读#

有这样的一种场景,A事务在读取表中的数据,不巧的是B事务也在操作这张表,并且刚刚添加了一条数据,然后A事务读到了,不幸的是,B事务失败了发生回滚,于是这条数据添加失败了,也就不会添加到数据库中。这样就可以说,A事务读取到了一条“脏”数据,这种读到了脏数据的现象就叫做脏读
“脏数据”就是临时产生的,或是运行过程中出现过但最终没有被写入到数据库中的数据。

幻读#

还是A和B两个事务在操作同一个表,A一直在查询表中的数据,而B在向表中添加或删除数据,于是从A的角度来看就发生了很诡异的现象,每次查询查到的数据量不同,A寻思自己也妹添加删除数据啊,就好像出现了幻觉一样。

不可重复读#

不可重复读是针对另一个事务在修改数据而言的,还是事务A一直在查询,然后事务B在修改同一张表中的数据,于是A查出的数据虽然数量一致,但是内容却一直在变化。

前面也提到过,任一事务对其他事务都是透明的,每个事务都认为只有自己在操作数据库,那么只要在同一个事务中,无论什么时候执行查询,查到的数据都应该是一模一样的。所以脏读、幻读和不可重复读都是需要解决的问题。

隔离等级#

隔离等级依次更严格,效率则对应降低:

  1. 读未提交(read uncommitted)
  2. 读提交(read committed)
  3. 可重复读(repeatable read)
  4. 串行化(serialable)

数据库通过设置隔离等级来约束这些问题是否发生,可以在数据库的配置文件中修改默认等级,也可以通过命令修改当前会话的隔离等级,例如在pgSQL中可以执行set transaction isolation level REPEATABLE READ;来设置当前会话的隔离等级是可重复读。
下表展示了各个隔离等级中,脏读、不可重复读和幻读是否会发生。

隔离等级 脏读 不可重复读 幻读
读未提交(read uncommitted)
读提交(read committed) ×
可重复读(repeatable read) × ×
串行化(serialable) × × ×

四个等级正好对应了三种问题的约束,一般数据库的默认隔离等级是读提交,也就是可以避免脏读,但不保证幻读和不可重复读不会发生。另外在pgSQL中通过一些技术保证了即使隔离等级是读未提交也不会发生脏读。

读提交隔离等级下,事务中的每个读操作都会看到在该操作开始时已经提交的所有数据的最新版本。这意味着,如果一个事务在执行过程中,其他事务提交了更新,那么这些更新对于当前事务是可见的。为了避免脏读,PostgreSQL 通过 MVCC 确保每个事务只能看到已经提交的数据版本。读操作不会阻塞写操作,写操作也不会阻塞读操作,从而提供了良好的并发性能。

可重复读隔离等级下,事务中的所有读操作都会看到相同的数据快照,即使其他事务在本事务执行期间提交了更新。这个快照是在事务开始时创建的,所以即使其他事务提交了更新,当前事务中的查询也不会受到影响。PostgreSQL 通过 MVCC 确保事务开始时的数据版本被保存,以便在事务中的任何时刻重新读取相同的数据。这个级别解决了不可重复读的问题,但仍然可能遇到幻读。

串行化是最高的隔离等级,在这一等级下,通过严格的锁机制来确保事务的串行执行。在这个级别下,事务会获取必要的行级锁,以防止其他事务对这些数据进行修改或删除。由于使用了锁,这个级别可以避免幻读和其他并发问题,确保事务的执行就像所有操作都是串行执行的一样。这种机制提供了最强的数据一致性保证,但可能会大大降低并发性能,因为它限制了并发操作的数量。

作者:cwtxx

出处:https://www.cnblogs.com/cwtxx/p/18718183

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   cwtxx  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示