初识事务,本人先总结事务四大特点,然后给出个人对事务隔离等级的理解。
- 在执行SQL语句的时候,某些业务要求,一系列操作必须全部执行,而不能仅执行一部分。
例如,一个转账操作:
-- 从id=1的账户给id=2的账户转账100元
-- 第一步:将id=1的A账户余额减去100
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 第二步:将id=2的B账户余额加上100
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
这两条SQL语句必须全部执行,或者,由于某些原因,如果第一条语句成功,第二条语句失败,就必须全部撤销。
这种把多条语句作为一个整体进行操作的功能,被称为数据库事务。数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。如果事务失败,那么效果就和没有执行这些SQL一样,不会对数据库数据有任何改动。
可见,数据库事务具有ACID这4个特性:
A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
C:Consistent,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;
I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。
- 隔离级别
对于两个并发执行的事务,如果涉及到操作同一条记录的时候,可能会发生问题。因为并发操作会带来数据的不一致性,包括脏读(Dirty Read)、不可重复读(No Repeatable Read)、幻读(Phantom Read)等。数据库系统提供了隔离级别来让我们有针对性地选择事务的隔离级别,避免数据不一致的问题。
隔离等级 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 是 | 是 | 是 |
读提交 | 否 | 是 | 是 |
可重复读 | 否 | 否 | 是 |
可串行化 | 否 | 否 | 否 |
下面以事务A和事务B举例,给出个人的一些见解。
- 读未提交:这个隔离级别下,事务A会读到事务B中未提交的数据。在事务B回滚后,事务A读到的数据无意义,是脏数据,成为脏读。
- 读提交:这个隔离级别下,只有事务B已提交时,事务A才能读到。例如,如果事务A先查询了id为1的记录,之后事务B再修改这条记录并提交,当事务A再次读取该数据时,两次得到的结果并不一致,所以称之为不可重复读。
- 可重复读:这个隔离级别下,就算事务B对数据作出的修改已经提交,但事务A在事务B的执行过程中多次读到的数据是一致的。当事务B插入一条新数据并提交后,事务A查询不到这个新的数据,所以认为不存在这个数据。但是事务A却能成功更新这条数据,并且在更新之后再次查询时,是可以查到该数据的。因此,一开始查询不到却能修改,再次查询又出现了,像是产生了幻觉一样,所以称为“幻读”。
- 可串行化:事物之间相互独立,不存在并发。最严格的隔离等级,安全正确,但是效率不高。
由此可见,隔离性是事务的基本特性之一,它可以防止数据库在并发处理时出现数据不一致的情况。最严格的情况下,可用串行化方法执行每一个事务。然而在实际生产环境下,考虑到随着客户的增多,会存在大规模数据并发访问的情况,这就要求数据库有更高的吞吐能力,此时串行化的方式就无法满足数据库高并发访问的需求,我们还需要降低数据库的隔离等级来换取事务之间的并发能力。