什么是MySQL事务?
事务是由MySQL的引擎来实现的,我们常用的InnoDB引擎就是支持事务的,事务(Transaction)是一系列的数据库操作,这些操作要么全部成功执行,要么全部回滚(即全部失败,回到操作前的状态),这样确保数据库的数据在并发访问的情况下保持一致性和完整性。
举例:小A向小B转账50元,转账的流程是先从小A账户中扣除50元,然后向小B账户中增加50元,这两个流程就形成了一个完整的操作,不可拆分,这个操作过程就可以被称为一个事务。
如果这个事务能够被完整地执行,也就是说,小A账户成功扣除了50元并且小B账户成功增加了50元,那么这个事务就被认为是成功的,数据库中的数据就保持了一致性,即小A的总金额减少了50元,小B的总金额增加了50元。
但是,如果小A在转账的过程中发生了问题,比如银行的数据库出现故障、网络中断等,导致其中一个操作失败,那么整个事务就会被回滚,即两个操作都不执行,数据库中的数据保持原样,这样可以避免数据的不一致性。
如果没有事务机制,可能会导致转账过程中出现数据错误,例如小A账户扣了钱但没有成功向小B账户增加钱,或者反之,从而导致数据的不一致和不可靠性。
事务必须具备的四个条件(ACID)
一个完整的事务必须具备四个条件,这四个条件我们称为“ACID特性”,ACID特性确保了一个完整的事务在数据库中的正确执行和数据的一致性。“ACID”这四个字母,每个字母代表了一个特性。
原子性(Atomicity):事务(transaction)被视为一个不可分割的单元,要么全部执行成功,要么全部不执行。如果在事务的执行过程中发生错误,那么事务会被回滚到开始前的状态,保持数据的一致性。
一致性(Consistency):事务在执行前和执行后,数据库的数据应该处于一致的状态。这意味着事务在执行时,必须遵守一些预定的规则或约束,以保持数据的正确性。
隔离性(Isolation):事务之间是相互隔离的,一个事务的执行不会被其他事务干扰。这意味着并发执行的事务不会相互影响,可以保证数据的完整性和正确性。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
持久性(Durability):一旦事务成功提交,对数据库的修改将永久保存,即使在系统故障或崩溃后,数据也不会丢失。持久性确保数据的持久性存储,保障数据的可靠性。
事务的隔离级别
事务隔离级别的主要目的是解决数据库并发访问时可能出现的以下问题:
脏读(Dirty Read):一个事务读取了另一个事务尚未提交的数据,如果另一个事务回滚,则读取到的数据实际上是无效的,这种现象就被称为脏读,如下图所示。
不可重复读(Non-repeatable Read):在同一个事务内,由于其他事务对”同一行“数据进行了修改(更新或删除),导致在多次读取该行数据时,得到的结果不一致。这意味着同一个事务内的两次读取操作得到了不同的数据值。重点在于其他事务的更新(update)和删除(delete)。
幻读(Phantom Read):在同一个事务内,由于其他事务对数据进行了插入(insert)或删除(delete)操作,导致多次查询时得到的结果集不一致。幻读主要发生在”范围查询“中,即同一个事务内的两次查询得到了不同数量的结果行。重点在于其他事务的插入(insert)和删除(delete)。MySQL官方原文:The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row. (https://dev.mysql.com/doc/refman/8.0/en/innodb-next-key-locking.html)
为解决以上问题可以通过设置不同的事务隔离级别,可以控制这些问题的发生概率。MySQL支持以下四种事务隔离级别。
读未提交(Read uncommitted):最低级别的隔离,允许一个事务读取另一个事务“尚未提交“的数据。这可能导致脏读、不可重复读和幻读问题。
读已提交(Read Committed):允许一个事务读取另一个事务已提交的数据,解决了脏读问题。但是仍可能出现不可重复读和幻读问题。
可重复读(Repeatable Read):这是MySQL InnoDB引擎的默认隔离级别,保证在一个事务内多次读取同一数据时,结果始终一致。解决了脏读和不可重复读问题。但是仍可能出现幻读问题。
串行化(Serializable):最高级别的隔离,确保同时只有一个事务能够访问数据,解决了脏读、不可重复读和幻读问题。但是串行化会导致并发性能大幅下降,因为多个事务无法同时访问数据。
隔离级别高低排序如下:
隔离级别以及可能产生的读现象:
总结:应结合实际的业务需求,可以选择适合的隔离级别来处理数据并发操作。但隔离级别越高,性能可能越差,因为它需要锁定更多的资源以保证数据的一致性。因此,在设计事务时,需要综合考虑业务的要求和性能的影响。
本文仅代表吴昊个人观点,如有错误欢迎留言指出!
原文链接:MySQL事务原理讲解,转载请注明来源!