🐇MySQL事务

定义

事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。

事务的结果有两种:当事务中的所有步骤全部成功执行完成时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消之前到事务开始时的所有操作。

事务的四个特性

事务具有四个特征:

原子性( Atomicity )

一致性( Consistency

隔离性( Isolation )

持久性( Durability )

这四个特性简称为 ACID 特性。

  • 原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性: 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  • 隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读已提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • 持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

MySQL的四种隔离级别

一、读未提交

读未提交(Read Uncommitted)是数据库事务隔离级别中最低的级别之一,也是最弱的隔离级别。在读未提交的隔离级别下,一个事务可以读取另一个事务尚未提交的数据修改,这意味着事务之间没有任何隔离,可能会导致脏读(Dirty Read)问题。

具体来说,读未提交的隔离级别具有以下特点:

① 允许脏读:事务A可以读取事务B尚未提交的数据修改。如果事务B在某个数据行上进行了修改但尚未提交,事务A仍然可以读取到被修改后的数据,这可能导致脏读问题。脏读指的是一个事务读取到了另一个事务尚未提交的数据,而后者可能会在后续被回滚,从而导致读取到的数据实际上是无效的。

② 不保证一致性:由于允许脏读,读未提交的隔离级别无法保证事务的一致性。事务A在读取数据时可能会读取到其他事务尚未提交的数据修改,导致数据的不一致性。

③ 低并发性:由于允许脏读,数据库系统在读未提交的隔离级别下需要较少的并发控制和锁定操作。这使得读未提交的隔离级别具有较低的并发性,但也增加了数据不一致的风险。

总结:读未提交的隔离级别通常用于一些对数据一致性要求不高、并发性要求较高的场景,例如某些只读取数据而不进行更新的报表查询或者临时数据分析任务。但是在大多数生产环境中,读未提交的隔离级别往往是不推荐使用的,因为它可能导致数据的不一致性,增加系统出错的风险。

二、读已提交

读已提交(Read Committed)是数据库事务隔离级别中较为常见的一种级别。在读已提交的隔离级别下,一个事务只能读取到已经提交的数据修改,这意味着事务之间具有部分隔离性,可以避免脏读(Dirty Read)问题。

以下是读已提交隔离级别的一些特点和行为:

① 已提交数据可见:事务在读取数据时只能读取到已经提交的数据修改。这意味着其他事务尚未提交的数据修改对当前事务是不可见的,从而避免了脏读问题。

② 一致性保证:由于只能读取到已提交的数据修改,读已提交的隔离级别可以保证事务读取到的数据是一致的。这确保了事务的读操作不会读取到不一致的数据。

③ 不可重复读:读已提交隔离级别下,同一个事务在不同的时间点多次读取同一行数据,可能会得到不同的结果。这是因为在两次读取之间,其他事务可能会提交对数据的修改,导致数据不一致。这种情况称为不可重复读(Non-Repeatable Read)。

④ 无法解决幻读问题:读已提交隔离级别无法完全解决幻读(Phantom Read)问题。幻读指的是在同一个事务中多次执行相同的查询,但是结果集却不一致,通常是由于其他事务插入或删除了符合查询条件的数据。虽然读已提交隔离级别可以保证读取到的数据是已提交的,但并不保证查询结果的一致性。

总结:读已提交隔离级别提供了一定程度的数据隔离,避免了脏读问题,并保证了读取到的数据是一致的。但是由于无法解决不可重复读和幻读问题,因此在某些应用场景下仍可能需要更高级别的隔离级别。

三、可重复读

可重复读(Repeatable Read)是数据库事务隔离级别中的一种,它提供了比读已提交更高的隔离性。在可重复读隔离级别下,一个事务在执行过程中多次读取同一行数据,可以得到一致的结果,即使其他事务对数据进行了修改也不会影响到当前事务的读取结果。

以下是可重复读隔离级别的一些特点和行为:

① 保证一致性:在可重复读隔离级别下,一个事务在执行过程中多次读取同一行数据,得到的结果始终保持一致。即使其他事务对数据进行了修改,这些修改对当前事务都是不可见的。

② 防止不可重复读:可重复读隔离级别解决了读已提交隔离级别中的不可重复读(Non-Repeatable Read)问题。即使其他事务对数据进行了修改,当前事务多次读取同一行数据时,结果仍然保持不变。

③ 防止幻读:可重复读隔离级别也可以一定程度上防止幻读(Phantom Read)问题。幻读指的是在同一个事务中多次执行相同的查询,但是结果集却不一致,通常是由于其他事务插入或删除了符合查询条件的数据。虽然可重复读隔离级别可以保证读取到的数据是一致的,但并不保证查询结果的完全一致性。为了完全避免幻读,可能需要更高级别的隔离级别,如串行化。

④ 事务内一致性:在可重复读隔离级别下,一个事务内部的操作是相互隔离的,即使事务中的多个查询操作之间存在依赖关系,也不会受到其他事务的影响。

总结:可重复读隔离级别提供了较高的隔离性,保证了事务内部多次读取同一行数据的一致性,避免了不可重复读问题。但是在高并发环境下,可能仍然会出现幻读问题,因此在对数据一致性要求极高的场景中,可能需要选择更高级别的隔离级别。

四、串行化

串行化(Serializable)是数据库事务隔离级别中最高的级别,也是最严格的隔离级别。在串行化隔离级别下,数据库系统确保事务之间的并发执行具有串行化的效果,即每个事务都像是按顺序执行一样,不存在并发执行的情况。

以下是串行化隔离级别的一些特点和行为:

① 完全隔离:在串行化隔离级别下,事务之间具有完全的隔离性,每个事务都像是在独立的执行环境中执行一样,互不干扰。这意味着不存在并发冲突,事务之间没有交叉执行的情况。

② 避免所有并发问题:串行化隔离级别可以完全避免所有的并发问题,包括脏读、不可重复读和幻读等。因为事务之间是串行执行的,不存在并发修改或者读取数据的情况,所以不会出现任何并发问题。

③ 性能影响:由于串行化隔离级别要求事务之间完全串行执行,因此可能会对系统的性能产生较大的影响。因为事务无法并发执行,可能会导致系统的吞吐量下降,响应时间延长。

④ 死锁风险:由于串行化隔离级别要求事务串行执行,可能会导致死锁的风险增加。如果多个事务之间存在循环依赖关系,并且都持有对方需要的资源锁,就可能导致死锁的发生。

总结:串行化隔离级别提供了最高的隔离性,可以完全避免所有的并发问题。但是由于其严格的执行顺序要求,可能会对系统的性能产生较大的影响。因此,在选择串行化隔离级别时,需要综合考虑数据一致性的要求和系统性能的需求,以及是否能够承受可能出现的死锁风险。

事务的隔离级别
事务的隔离级别 脏读 不可重复读 幻读
Read uncommitted(读未提交)
Read committed(读提交) ×
Repeatable read(重复读) × ×
Serializable(串行化) × × ×

总结

大多数数据库默认的事务隔离级别是Read committed(读提交),比如Sql Server , Oracle。

Mysql的默认隔离级别是Repeatable read(重复读)。

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed(读提交),它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

注意:事务的隔离级别和数据库的并发性是成反比的,隔离级别越高,并发性越低。