MySQL事务ACID四大特性和四大隔离级别

Posted by thinkwei on August 28, 2024

在 MySQL 中,事务的隔离级别用于控制多个事务之间的隔离程度,以避免数据的不一致性和并发问题。MySQL 主要有以下四种隔离级别:

1. 读未提交(Read uncommitted):
    
    允许一个事务读取另一个事务未提交的数据。这是最低的隔离级别,会导致脏读、不可重复读和幻读问题。
  
    举例:事务 A 修改了一条数据但未提交,事务 B 可以读取到这个未提交的数据。
  
    如果事务 A 回滚,事务 B 读取到的数据就是错误的,即发生了脏读。

2.读已提交(Read committed):
    
    一个事务只能读取另一个事务已经提交的数据。可以避免脏读,但可能会出现不可重复读和幻读问题。

    举例:事务 A 多次读取同一数据,在这个过程中,事务 B 对该数据进行了修改并提交。

    事务 A 每次读取到的数据可能不同,即发生了不可重复读。

3.可重复读(Repeatable read):
    
    在一个事务中,多次读取同一数据时,结果是一致的。可以避免脏读和不可重复读,但可能会出现幻读问题。

    MySQL 的默认隔离级别。举例:事务 A 读取了一个范围内的数据,在这个事务执行过程中,

    事务 B 在这个范围内插入了新的数据并提交。事务 A 再次读取这个范围的数据时,

    不会看到事务 B 插入的数据,避免了不可重复读。但如果事务 A 进行范围查询统计数量等操作,

    可能会出现前后结果不一致的情况,即幻读。

4. 串行化(Serializable):
    
    最高的隔离级别,通过强制事务串行执行来避免所有并发问题。

    事务在执行过程中会对涉及的数据加锁,其他事务必须等待这个事务执行完才能对这些数据进行操作。

    虽然可以保证数据的一致性,但会极大地降低数据库的并发性能。

    在实际应用中,可以根据业务需求选择合适的隔离级别。

    如果对数据一致性要求非常高,可以选择较高的隔离级别,但要注意性能开销。如果对性能要求较高,

    可以选择较低的隔离级别,但需要在代码中处理可能出现的并发问题。

mysql四大特性

  MySQL 具有四大特性,分别是原子性、一致性、隔离性和持久性,通常被称为 ACID 特性。
  
  一、原子性(Atomicity)

        原子性确保事务中的所有操作要么全部成功执行,要么全部不执行。如果事务中的任何一个操作失败,
      
        整个事务都会回滚到事务开始之前的状态。
      
        例如,你在进行银行转账操作时,从账户 A 转出一定金额到账户 B,这个过程包括两个操作:

        从账户 A 中减去转出金额和在账户 B 中增加转出金额。这两个操作要么同时成功,

        要么同时失败,不能出现只执行了其中一个操作的情况。
  
  二、一致性(Consistency)

        一致性是指在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏。
      
        也就是说,数据库中的数据必须始终保持合法的状态。

        例如,在一个库存管理系统中,库存数量不能为负数。如果一个事务试图将库存数量减少到负数,

        那么这个事务就会被回滚,以确保数据库中的数据始终满足库存数量不能为负数这个约束条件。
  
  三、隔离性(Isolation)
        
        隔离性是指多个事务并发执行时,它们之间相互隔离,互不干扰。

        每个事务都感觉不到其他事务的存在,就好像在独立地使用数据库一样。

        MySQL 通过不同的隔离级别来实现隔离性,如读未提交、读提交、可重复读和串行化等隔离级别,

        不同的隔离级别对并发事务的隔离程度不同,从而在性能和数据一致性之间进行权衡。

  四、持久性(Durability)

        持久性是指一旦事务提交成功,对数据库所做的修改就会永久保存下来,即使系统发生故障也不会丢失。

        MySQL 通常使用日志和磁盘存储来保证持久性。当事务提交时,数据库会将修改的数据和相应的日志记录写入磁盘,

        以便在系统发生故障时能够恢复数据。

可重复读隔离级别是如何避免幻读的?

  在 MySQL 的可重复读隔离级别下,主要通过以下几种方式来尽量避免幻读:
  
  一、MVCC(多版本并发控制)
        
        MVCC 允许事务看到一个特定时间点的数据快照。在可重复读隔离级别下,事务在第一次查询时建立一个快照,
      
        后续的查询都基于这个快照进行,不受其他事务插入、删除数据的影响。
      
        例如,事务 A 开始执行并进行一次查询,此时建立了数据快照。
        
        在事务 A 执行过程中,其他事务插入了新的数据行,但事务 A 在后续的查询中仍然基于初始快照进行,
      
        不会看到这些新插入的行,从而避免了幻读现象中查询结果集的变化。
  
  二、间隙锁(Gap Lock)
        
        间隙锁可以锁定一个范围,但不包括范围的端点。在可重复读隔离级别下,对于特定的查询条件,

        如果查询涉及到范围查询,MySQL 会使用间隙锁来防止其他事务在这个范围内插入新的数据行。

        例如,事务 A 要查询一个范围的数据,比如 id 在 10 到 20 之间的记录,

        此时 MySQL 会对这个范围加上间隙锁,阻止其他事务在这个范围内插入 id 为 11、12 等新的记录,

        避免了幻读现象中出现新的数据行满足查询条件。

        需要注意的是,虽然可重复读隔离级别在一定程度上可以避免幻读,但并不能完全消除幻读的可能性。

        在某些特殊情况下,比如使用允许幻读的语句或者涉及到外键约束等情况,仍然可能出现幻读现象。

幻读和不可重复读的区别是什么?

  幻读和不可重复读都是数据库事务隔离级别中可能出现的问题,它们的区别如下:
    
  一、定义不同
        
        不可重复读:是指在一个事务内多次读取同一数据集合,在这个事务还没有结束时,
        
        如果另一个事务恰好修改了这个数据集合中的数据并提交,那么第一个事务多次读取的数据可能不一样。
        
        例如,事务 A 读取某一行数据,事务 B 修改了这行数据并提交,事务 A 再次读取这行数据时发现值不同了。
  
  幻读:是指一个事务在两次查询中得到的结果集不一样,第二次查询的结果集中包含了第一次查询中没有出现过的数据行,
    
    或者第一次查询中的某些数据行在第二次查询中消失了。例如,事务 A 按照某个条件进行范围查询,
    
    事务 B 插入了一些满足事务 A 查询条件的数据行并提交,

    事务 A 再次执行相同的范围查询时,结果集中多了一些数据行。

  二、针对的数据操作不同
        不可重复读:主要针对的是数据的修改操作(UPDATE),
      
        即一个事务对同一数据的修改导致另一个事务前后两次读取结果不同。

  幻读:主要针对的是数据的插入和删除操作(INSERT 和 DELETE),
      
        即一个事务对数据的插入或删除导致另一个事务前后两次查询结果集不同。

  三、影响范围不同

        不可重复读:影响的是同一行数据的读取结果。

        幻读:影响的是整个查询结果集,涉及多行数据。

  四、解决方法不同
  
        不可重复读:在可重复读隔离级别下,通过使用 MVCC(多版本并发控制),

        事务在第一次读取数据时建立一个快照,后续的读取都基于这个快照进行,

        从而避免了其他事务对同一数据的修改导致的不可重复读问题。

  幻读:在可重复读隔离级别下,除了使用 MVCC,

        还通过间隙锁来防止其他事务在查询范围内插入新的数据行,
      
        从而避免幻读问题。但间隙锁也不能完全消除幻读的可能性,在一些特殊情况下仍可能出现幻读现象。

        在串行化隔离级别下,可以完全避免幻读问题,但会极大地降低数据库的并发性能。

脏读是什么 以及如何避免的

  一、脏读的定义
  
    脏读是指一个事务读取到了另一个事务未提交的数据。例如,事务 A 修改了一条数据但还未提交,
  
    此时事务 B 读取了这条被事务 A 修改过的数据。如果事务 A 最终回滚了这个修改,
  
    那么事务 B 读取到的数据就是错误的,这种情况就称为脏读。
  
  二、避免脏读的方法
  
    在数据库中,可以通过设置适当的事务隔离级别来避免脏读。常见的方法有以下两种:
  
    使用较高的事务隔离级别
  
    例如在 MySQL 中,将事务隔离级别设置为读提交(Read Committed)
  
    或更高的可重复读(Repeatable Read)、串行化(Serializable)级别。
  
    读提交隔离级别下,一个事务只能读取到其他事务已经提交的数据,
  
    避免了读取未提交的数据,从而防止脏读。
  
    可重复读隔离级别和串行化隔离级别对数据的隔离性更强,也能避免脏读问题。
  
    合理设计事务和操作流程
  
    确保事务在对数据进行修改时,尽快提交或回滚,减少数据处于未提交状态的时间。
  
    避免在事务中进行长时间的复杂操作,以降低其他事务读取未提交数据的风险。
  
    对于关键业务数据,可以采用加锁等方式来控制并发访问,防止脏读的同时保证数据的一致性。