事务是现代关系型数据库的核心之一。在多个事务并发操作数据库(多线程、网络并发等)的时候,如果没有有效的避免机制,就会出现以下几种问题:
脏读(Dirty Read)
A事务执行过程中,B事务读取了A事务的修改。但是由于某些原因,A事务可能没有完成提交,发生RollBack了操作,则B事务所读取的数据就会是不正确的。这个未提交数据就是脏读(Dirty Read)
场景图:
导致脏读的原因:数据库事物使用了READ UNCOMMITTED(未提交读) 允许session1读取session2未提交的事物。
解决脏读:数据库事物使用READ COMMITTED(已提交读:默认)不允许session1读取session2未提交的事物。
不可重复读(Nonrepeatable Read)
B事务读取了两次数据,在这两次的读取过程中A事务修改了数据,B事务的这两次读取出来的数据不一样。B事务这种读取的结果,即为不可重复读(Nonrepeatable Read)。不可重复读的产生的流程如下:
导致不可重复读的原因:数据库事物使用了READ UNCOMMITTED(未提交读)或者READ COMMITTED(已提交读:默认) 允许session1读取session2提交的事物。
解决不可重复读:数据库事物使用REPEATABLE READ(可重复读)在session1事物未提交之前 不允许session2修改数据。
幻读(Phantom Read)
B事务读取了两次数据,在这两次的读取过程中A事务添加了数据,B事务的这两次读取出来的集合不一样。幻读产生的流程如下:流程看起来和不可重复读差不多,但幻读强调的集合的增减,而不是单独一条数据的修改。
导致幻读的原因:数据库事物使用了READ UNCOMMITTED(未提交读)或者READ COMMITTED(已提交读:默认)或者 REPEATABLE READ(可重复读) 允许session1读取session2提交的事物。
解决幻读:数据库事物使用ERIALIZABLE (可序列化) 在session1事物未提交之前 不允许读取session2修改数据。
数据库隔离级别
为了解决上面提及的并发问题,主流关系型数据库都会提供四种事务隔离级别。
读未提交(Read Uncommitted)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别是最低的隔离级别,虽然拥有超高的并发处理能力及很低的系统开销,但很少用于实际应用。因为采用这种隔离级别只能防止第一类更新丢失问题,不能解决脏读,不可重复读及幻读问题。
读已提交(Read Committed)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别可以防止脏读问题,但会出现不可重复读及幻读问题。
可重复读(Repeatable Read)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。这种隔离级别可以防止除幻读外的其他问题。改隔离是行锁
可串行化(Serializable)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读、第二类更新丢失问题。在这个级别,可以解决上面提到的所有并发问题,但可能导致大量的超时现象和锁竞争,通常数据库不会用这个隔离级别,改隔离是表锁
这四种隔离级别会产生的问题如下:
注:该文章中所有的图片均不是本人所创,素材来源于其他博客或者文章