一、 事务及事务隔离级别
以下内容围绕:
事务是什么?
事务是作为单个逻辑工作单元执行得一系列操作,也就是“要么全部执行,要么全部不执行”。
假如 A 要去银行取款 100 元,这次的取款过程会涉及两个操作:
事务的 ACID 特性
事务必须要有四个属性:
原子性(Atomicity):即不能再更细的分割了。事务操作必须是原子的,对于一个事务中的所有操作,要么全部执行(COMMIT),要么全部不执行(ROLLBACK)。
一致性(Consistency):一致性指的是数据的完整性,即执行事务的前后,数据整体应该是一致的。事务必须能够让数据库从一个一致性状态变换到另一个一致性状态。对于取款的案例来说,A 的数据总值就是一致的。
隔离性(Isolation):它指的是一个事务的执行不能被其他事务所干扰,这里又涉及到并发的概念。一个事务内部的操作对其他并发的事务是隔离的,简单的说,每个事务都认为是自己独占数据库。
持久性(Durability):一个事务一旦提交(COMMIT),它对数据库中数据的改变就是永久性的。任何操作甚至是系统故障都不应该对其产生影响
InnoDB 存储引擎默认的事务隔离级别是可重复读,它不能满足隔离性要求
并发事务会带来什么样的问题
多线程程序中,如果在并发运行的过程中对相同的数据进行了修改,就可能会引起一些问题,总结下来,可能出现的问题一共有三种:脏读、不可重复读、幻读。
脏读:事务A读取了事务B当前更新的数据,但是事务B出现了回滚或未提交,事务A读到的数据就被成为“脏数据”
不可重复读:事务A在执行过程中多次读取同一个数据,但是事务B在事务A的读取过程中对数据做了多次修改并提交,则会导致事务A多次读取的数据不一致,进而无法做出数据准确性判断。
幻读:事务 A 在执行过程中读取了一些数据,但是事务 B 随即插入/删除数据了一些数据,那么,事务 A 重新读取时,发现多了一些原本不存在的数据/少了一些数据,就像是幻觉一样,称之为幻读
不可重复读与幻读从概念上来说,是非常相似的。区分它们只要记住:不可重复读指的是对原来存在的数据做修改,而幻读指的是新增或者删除数据。
二、 解读事务隔离级别
SQL 标准定义了四种隔离级别,由低到高依次为:
READ-UNCOMMITTED(未提交读):它是最低的隔离级别,正如它的名称一样,它允许一个事务读取其他事务未提交的数据。这个隔离级别很少在工业环境中应用,因为它的性能并不会比其他高级别的性能好很多
READ-COMMITTED(提交读):它可以保证一个事务修改的数据提交之后才能被其他的事务读取。这个隔离级别是大多数数据库系统的默认隔离级别,但并不是 MySQL 默认的
REPEATABLE-READ(可重复读):它的核心在于 “可重复”,即在一个事务内,对同一字段的多次读取结果都是相同的,也是 MySQL 的默认事务隔离级别
SERIALIZABLE(串行化):是最高的隔离级别,花费的代价也是最高的,事务的处理是顺序执行的。在这个级别上,可能会导致大量的锁超时现象和锁竞争。同样,在工业级环境中,很少被使用
它们可以逐个解决脏读、不可重复读、幻读这几类问题,除 SERIALIZABLE 之外的另外三种都不能解决所有的问题。所以,在实际的应用中,一定是有所取舍的。
隔离界别解决的问题:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | No | No | No |
READ-COMMITTED | Yes | No | No |
REPEATABLE-READ | Yes | Yes | No |
SERIALIZABLE | Yes | Yes | Yes |
具体选择哪一种隔离级别应该是多个维度的考虑,例如:事务请求锁的多少(性能问题)、能够解决什么问题、业务特点等等。一般情况下,使用 InnoDB 存储引擎,我们会选择 READ-COMMITTED。