MySQL数据库事务的基本特性以及4种隔离级别

详细介绍了Mysql数据库事务的基本概念、并发事务的问题、事物的实现原理以及隔离级别。

在数据库中,事务是数据库操作的最小逻辑工作单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整个工作单元操作,要么一个也不执行(都失败)。

重要的是,一个事务当中的所有操作要么都成功,要么都失败,这样的特性,保证了用户每一个操作的可靠性,即使中途出现异常,也不会破坏原来的数据。比如常见的转帐案例,因为转账操作分为多个步骤,这就要用事务来处理,用以保证数据的一致性。

MySQL的InnoDB 引擎支持事务,而MyISAM则不支持事务。

文章目录

  • 1 事物的特性
  • 2 并发事务的问题
  • 3 事务的简单实现原理
  • 4 事务的隔离级别

1 事物的特性

  1. Atomicity:原子性,事务的不可分割的,事务的所有操作要么都成功,要么都失败。
  2. Consistency:一致性,多个客户端进行同时访问的时候,通过事务可以对多个客户端保持数据的一致性。例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
  3. Isolation:事务的隔离性,多个事务并发操作的时候,多个事务之间互相不影响,彼此独立。
  4. Durability: 事务的持久性,数据的改变通过事务的提交可以永久的保存在数据库当中,即使数据库发生故障也不应该对其有任何影响。

2 并发事务的问题

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

  1. 更新丢失(Lost Update)
    1. 当多个事务选择同一行操作,并且都是基于最初选定的值,由于每个事务都不知道其他事务的存在,就会发生更新覆盖的问题。类比github提交冲突。
  2. 脏读(Dirty Read)
    1. 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,这就叫脏读。脏读导致一个事务读取了被其他事务修改但还未提交的数据。
    2. 如:事务T1修改了一条数据,但是还未提交,事务T2此时读取到了这条修改后了的数据,如果此时T1将事务回滚,这个时候T2读取到的数据就是脏数据。
  3. 不可重复读(Non-Repeatable Read)
    1. 是指一个事务读取数据库中的数据后,另一个事务则修改或删除数据,当第一个事务再次执行同一查询时,就会发现数据已经发生了改变,这就是不可重复读。不可重复读所导致的结果就是一个事务前后两次读取的数据不相同,可以读取到其他事务更新/删除后的数据。
    2. 即不可重复读发生在一个事务执行两次或两次以上的相同查询时,查询结果不一致。这通常是由于另一个并发事务在两次查询之间修改/删除并提交了符合查询条件的数据。
    3. 如:事务T1按照条件读取一批记录,紧接着事务T2修改并提交了T1刚刚读取的那一批记录,然后T1再一次查询,发现与第一次读取的记录不同。
  4. 幻读(Phantom Read,不一定会发生)
    1. 是指一个事务读取数据库中的数据后,另一个事务则插入了数据数据,当第一个事务再次执行同一查询时,就会发现数据已经发生了改变,多出来了数据,这就是幻读。幻读所导致的结果就是一个事务前后两次读取的数据不相同,可以读取到其他事务新插入的数据。
    2. 即幻读发生在一个事务执行两次或两次以上的相同查询时,查询结果不一致。这通常是由于另一个并发事务在两次查询之间插入并提交了符合查询条件的数据。
    3. 如:事务T1按照条件读取一批记录,紧接着事务T2插入并提交了符合T1查询条件的记录,然后T1再一次查询,发现与第一次读取的记录不同。

3 事务的简单实现原理

  1. MySQL InnoDB 引擎通过undo log回滚日志来保证原子性。
  2. MySQL InnoDB 引擎使用 redo log重做日志 保证事务的持久性。
  3. MySQL InnoDB 引擎通过锁机制、MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ )。
  4. 保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。

关于这几种日志,我们在之前的文章中已经讲过了。

4 事务的隔离级别

数据库允许多个事务的并行,事物的隔离级别就用来表示此事务与其他并行事务的工作隔离的程度。例如,此事务能否看到来自其他事务的未提交的写入?不同的数据库有不同的默认事务隔离级别。由于并行事务,不同的隔离级别可能会带来不同的数据访问现象/安全问题。换句话说,事务的隔离级别是根据是否会出现上面讲的的某些现象来区分的!

在SQL92标准中,针对大部分数据库定义了4个标准的事务隔离级别:

  1. 读未提交(Read Uncommitted):就是一个事务可以并发的读取另一个未提交事务变更的数据。存在脏读、不可重复读、幻读的问题。
  2. 读已提交(Read Committed):一个事务可以并发的读取另一个事务提交后的数据。解决了脏读问题,还有不可重复读和幻读的问题。Sql Server , Oracle的默认隔离级别。
  3. 可重复读(Repeatable Read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。即事务在执行期间看到的数据前后必须是一致的。可能出现幻读。MySQL的默认隔离级别就是Repeatable Read。
    1. 实际上,mysql在默认的可重复读隔离级别下,mvcc的普通的查询是快照读,提供了一致性视图,不会看到别的事务插入的数据的,也就不存在所谓的“幻读”了,而如果使用当前读,那么则会加上行锁+Gap间隙锁,其他事务的插入操作则根本无法进行,因此实际上mysql的InnoDB引擎已经使用mvcc解决了幻读的问题(见《高性能MySQL》)。那么这里的幻读是什么呢?这里更多是指的oracle的操作,所以你用mysql测试的话,幻读很有可能测不出来。
    2. 当前读:select…lock in share mode (共享读锁)、select…for update、update语句、delete语句、insert语句
  4. 序列化/串行化(Serializable):Serializable 是最高的事务隔离级别,在该级别下,事务通过加锁的方式直接避免并行访问,可以避免脏读、不可重复读与幻读问题,严重影响程序性能。读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。

Oracle默认的隔离级别是read committed,还支持SERIALIZABLE。MySQL默认隔离级别: Repeatable Read,并支持全部四种级别。

可以用show variables like 'transaction_isolation';命令来查看当前的隔离级别:
MySQL数据库事务的基本特性以及4种隔离级别_第1张图片

在不同的隔离级别下,数据库行为是有所不同的。事务的隔离级别设置越高,异常就出现的越少,但并发效果就越低,事务的隔离级别设置越小,异常出现的越多,并发效果越高。

下一篇文章中,我们将介绍MySQL数据库事务的不同隔离级别的实现原理以及MVCC。

参考资料:

  1. 《 MySQL 技术内幕: InnoDB 存储引擎》
  2. 《高性能 MySQL》
  3. 《MySQL实战45讲 | 极客时间 | 丁奇》

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

你可能感兴趣的:(MySQL,mysql,数据库事务,ACID,隔离级别)