MySQL事务和隔离级别

什么是事务

事务是一组原子性的SQL查询,事务内的SQL语句,要么全部执行成功,要么全部执行失败

最经典的例子就是转账了,假如小明要给小红转账100元,这个转账会涉及到两个关键操作就是:将小明的余额减少100元,将小红的余额增加100元。如果在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就很麻烦了。

事务就是保证这两个关键操作要么都成功,要么都要失败。

事务的特性

事务具备 ACID 特性

  • 原子性(atomicity)
  • 一致性(consistency)
  • 隔离性(isolation)
  • 持久性(durability)。
原子性(atomicity)

一个事务被视为一个完整的最小工作单元,事务中的数据库操作,要么全部执行成功,要么全部执行失败回滚,不会存在只成功执行了其中的一部分数据库操作;

一致性(consistency)

数据库总是从一个一致性的状态转换到另一个一致性的状态。在银行转账的例子中,小明的钱减少了100,然后系统出错,因为执行失败时,事务进行了回滚,所做的修改并没有保存到数据库中;

隔离性(isolation)

一个事物所做的修改在提交以前,对其他事务是不可见的。在银行转账的例子中,小明的钱减少100时,此时另外一个程序在汇总支票账户,它所查询到小明账户,并没有减去100元人民币;

持久性(durability)

事务提交成功,所做的修改就会永久保存到数据库中,即使系统崩溃,修改的数据也不会丢失。

  • 事务是在存储引擎层实现的,MySQL 是支持多种存储引擎的数据库,
  • 并不是所有的存储引擎都支持事务,比如 MyISAM 就不支持事务。
  • 事务增加了数据库的安全性,同时也需要数据库做很多额外的工作,需要更强的 CPU、内存、以及磁盘空间。

并发事务带来的问题

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题:

脏读(Dirty read)

当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

丢失修改(Lost to modify)

一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。例如: 事务1读取某表中的数据i=10,事务2也读取i=10,事务1修改i=i-1,事务2也修改i=i-1,最终结果i=9,事务1的修改被丢失。

不可重复读(Unrepeatableread)

指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

幻读(Phantom read)

幻读与不可重复读类似。它发生在一个事务(T1) 读取了几行数据,接着另一个并发事务(T2) 插入了一些数据时。在随后的查询中,第一个事务(T1) 就会发现多了一些些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

不可重复读和幻读区别:
  • 不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改
  • 幻读的重点在于新增或者删除比如多次读取一条记录发现记录增多或减少了。

事务的隔离级别

在 SQL 标准中,包含了四种隔离级别,即未提交读(read uncommitted)、提交读(read committed)、可重复读(repeatable read)、可串行化(serializable)。

未提交读(read uncommitted)

一个事务还未提交,它所做的变更能被别的事务看到。事务可以读取未提交的数据,被称为脏读(dirty read),这种隔离级别在实际应用中一般很少使用;

提交读(read committed)

一个事务提交之后,它所做的变更才能被别的事务看到。大多数数据库的默认隔离级别是提交读(read committed),比如 Oracle;

可重复读(repeatable read)

一个事务在执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。在可重复读隔离级别下,未提交变更对其他事务也是不可见的。该级别保证了在同一个事务中,多次读取同样记录的结果是一致的。MySQL 的默认事务隔离级别是可重复读(repeatable read);

可串行化(serializable)

serializable 是最高的隔离级别。对同一行数据,读写都会进行加锁。当出现锁冲突时,后面访问的事务必须等前一个事务完成,才能继续执行。实际应用场景很少用到这种隔离级别,只有在非常需要确保数据一致性,而且可以接受没有并发的情况,才会使用这种隔离级别。

mysql8更改事务级别不生效 mysql事务等级_事务