当前位置: 首页 > 科技观察

本文带你轻松了解事务隔离级别(图文详解)

时间:2023-03-21 13:19:59 科技观察

什么是事务?事务是一组逻辑操作,可以执行也可以不执行。最经典的交易经常被引用为转账的例子。如果小明想转1000元给小红,这笔转账会涉及两个关键操作:减少小明余额1000元,增加小红余额1000元。万一这两个操作突然出现错误,比如银行系统崩溃,导致小明的余额减少,小红的余额没有增加,这是错误的。事务是为了确保这两个关键操作要么成功要么失败。事物的特征(ACID)?原子性:事务是最小的执行单元,不允许分割。事务的原子性确保动作全部完成或完全没有效果;?一致性:交易执行前后,数据保持一致;?隔离性:并发访问数据库时,一个用户的东西不受其他东西的干扰数据库在事务之间是独立的;?持久性:事务提交后。它对数据库中数据的改变是持久化的,即使数据库出现故障也不应该对其产生任何影响。并发事务带来的问题在一个典型的应用中,多个事务并发运行,往往对同一份数据进行操作,完成各自的任务(多个用户对统一数据进行操作)。虽然并发是必要的,但它可能会导致以下问题。?脏读:当一个事务正在访问数据并修改数据,而这个修改还没有提交给数据库时,另一个事务也访问了数据,然后使用了数据。因为这个数据是未提交的数据,另一个事务读取的数据是“脏数据”,基于“脏数据”的操作可能是错误的。?丢失修改(Losttomodify):当一个事务读取一个数据时,另一个事务也访问了该数据,那么在第一个事务修改了数据之后,第二个事务也修改了数据。这样第一笔交易中的修改结果就丢失了,所以称为丢失修改。例如:事务1读取了一张表中的数据A=20,事务2也读取了A=20,事务1修改了A=A-1,事务2也修改了A=A-1,最终结果为A=19,事务1修改丢失。?不可重复读(Unrepeatableread):指在一个事务中多次读取同一个数据。当这个事务没有结束时,另一个事务也访问了数据。那么,在第一个事务中的两次读取数据之间,由于第二个事务的修改,第一个事务两次读取的数据可能不同。这种情况恰好是一个事务中两次读取的数据是不同的,所以称为不可重复读。?幻读(Phantomread):幻读类似于不可重复读。当一个事务(T1)读取几行数据,然后另一个并发事务(T2)插入一些数据时,就会发生这种情况。在后续的查询中,第一个事务(T1)会多出一些不存在的记录,好像出现了幻觉,所以称为幻读。不可重复读和幻读的区别:不可重复读的重点是修改,幻读的重点是增删改查。例1(同样的条件,你读过的数据,再读一遍发现值不一样):事务1中的A先生还没有完成读取自己1000工资的操作,而事务中的B先生2将A的工资改为2000,导致A重新读取自己的工资时,工资改为2000;这是不可重复的阅读。示例2(相同条件,第一次和第二次读出的记录条数不同):工资单表中有4个人工资大于3000,事务1读取所有工资为大于3000,共找到4条记录。这时事务2又插入了一条工资大于3000的记录,事务1再次读取时,发现的记录变成了5条,导致幻读。事务隔离级别SQL标准定义了四种隔离级别:?READ-UNCOMMITTED(读未提交):最低的隔离级别,允许读取未提交的数据更改,这可能导致脏读、幻读或不可重复读?READ-COMMITTED(readcommitted):允许读取并发事务已经提交的数据,可以防止脏读,但幻读或不可重复读仍然可能发生REPEATABLE-READ(rereadable):多次读取同一个字段的结果每次读的都是一致的,除非数据被事务自己修改了,这样可以防止脏读和不可重复读,但是还是有可能会出现幻读。?SERIALIZABLE(可序列化):最高隔离级别,完全服从于ACID隔离级别。所有的事务都是一个一个执行的,这样事务之间就不存在相互干扰的可能,即这个级别可以防止脏读、不可重复读和幻读。MySQLInnoDB存储引擎默认支持的隔离级别是REPEATABLE-READ(可重读)。我们可以使用SELECT@@tx_isolation;命令查看mysql>SELECT@@tx_isolation;+----------------+|@@tx_isolation|+------------------+|REPEATABLE-READ|+----------------+这里需要注意的是,与SQL标准的区别在于InnoDB存储引擎使用了Next-KeyLock锁算法在REPEATABLE-READ(可重读)事务隔离级别下,因此可以避免幻读的产生,这是有别于其他数据库系统(如SQLServer)的。因此,InnoDB存储引擎默认支持的隔离级别是REPEATABLE-READ(可重读),可以充分保证事务的隔离要求,即达到了SQL标准的SERIALIZABLE(可序列化)隔离级别。因为隔离级别越低,事务请求的锁就越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交的内容):,但是需要知道的是InnoDB存储引擎使用的是REPEATABLE-READ默认情况下(可以重读)没有任何性能损失。InnoDB存储引擎一般在分布式事务的情况下使用SERIALIZABLE(可序列化)隔离级别。实际情况表明,在MySQL命令行的默认配置中,事务是自动提交的,即执行完SQL语句后,会立即执行COMMIT操作。如果要显式启动一个事务,需要使用命令:STARTTARNSACTION。我们可以使用以下命令设置隔离级别。SET[SESSION|GLOBAL]TRANSACTIONISOLATIONLEVEL[READUNCOMMITTED|READCOMMITTED|REPEATABLEREAD|SERIALIZABLE]下面看一下我们在实际操作中使用的一些并发控制语句:STARTTARNSACTION|BEGIN:显式开启一个事务。?COMMIT:提交事务,使对数据库所做的所有更改永久化。?ROLLBACK回滚将结束用户的事务并撤消正在进行的所有未提交的更改。下面我将使用2个命令行MySQL来模拟多线程(多事务)。Dirtyreads(readuncommitted)avoiddirtyreads(readcommitted)non-repeatablereads就在readcommitted图上面,虽然避免了readuncommitted,但是看起来一个事务还没有结束,一个unrepeatableRepeat的问题。可重复阅读防止幻读(repeatablereading)。事务对数据库进行操作。这个操作的范围是数据库的所有行,然后第二个事务也是对这个数据库进行操作。这个操作可以是插入一行记录,也可以是删除一行记录,那么首先事务会觉得自己有幻觉,为什么还有未处理的记录呢?或者如何处理额外的一行记录?幻读和不可重复读有一些相似之处,但是不能重复读的重点是修改,幻读的重点是增减。