数据库会有多种隔离级别,每种隔离级别都会带来不同的并发影响。
读未提交,即在事务还没有提交的时候,其他事务就可以来读,条件非常宽松,但可能会出现以下这种情况。
事务 T1 读的时候,事务 T2 还没有提交,T1 读到了数值 5,但 T2 最后回滚了,A 的值又变回了初始数值,这种情况就是脏读。
脏读(dirty read)指一个事务读取了另一个事务还未提交的修改。虽然大多数情况下,都会认为脏读产生了不正确的结果。但是脏读也不一定都是错误的情况,有时在数据要求并发量很高的情况下,甚至可以允许产生脏读。
为了应对上文这种情况,我们引入读提交,只有事务提交后,才能读到正确的数值,但可能会出现以下这种情况。
事务 T1 分别在事务 T2 提交前和提交后都读取了一次,两次读取的结果是不同,这其实违反了事务的隔离性,一个事务应该不需要知道其他事务的状态,这种情况叫做不可重复读。
不可重复度读(nonrepeatable read)指在一个事务过程中,可能出现多次读取同一数据但得到的值不同的现象。
可重复读,根据上文这种情况,我们再加一些条件,在事务执行过程中,不需要另外的数据对这部分数据进行改写,简单的想法就是加一个读锁,这样就避免了不可重复读的情况,但可能会产生以下这种情况。
事务 T1 在执行过程中,事务 T2 新增了一个数据,因为这部分数据不在读锁限制的范围内,所以插入数据是成功,因此 T1 再查询的时候,发现满足条件的结果产生了改变,这就是幻读。
幻读(phantom read)指在一个事务中,当查询了一组数据后,再次发起相同查询,却发现满足条件的数据被另一个提交的事务改变了。
根据上述的各种意外情况,最后我们让事务串行化,所有的事务必须按照一定顺序执行,直接避免了不同事务并发带来的各种问题。但这种方式代价也是巨大的,会导致数据库的并发能力特别差。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 可能出现 | 可能出现 | 可能出现 |
读提交 | 不能 | 可能出现 | 可能出现 |
可重复读 | 不能 | 不能 | 可能出现 |
可有序化 | 不能 | 不能 | 不能 |