数据库事务和四种隔离级别
三种bug:
脏读:
例:insert into T values (4, '牛D');
,然后没commit。
其他进程SELECT
读取到的数据是未commit的数据。(数据库只修改了内存没修改外存)
不可重复读:
例:一个事务范围内两个相同的查询却返回了不同数据(因为中间有进程修改了值并且提交成功)
幻读:
例:某个事务在读取某个范围的数据,但是另一个事务又向这个范围的数据去插入数据,导致多次读取的时候,数据的行数不一致。
READ UNCIMMITTED(未提交读)
在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。
READ COMMITTED(提交读)
就是只能读到已经提交了的内容。
为什么提交读,未提交读都没有查询加锁,但是却能够避免脏读呢?
这就要说道另一个机制-快照(snapshot)
当B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据......之后无论再有其他事务commit都没有关系,因为照片已经生成了,而且不会再生成了,以后都会参考这张照片。
假设没有“快照读”,那么当一个更新的事务没有提交时,另一个对更新数据进行查询的事务会因为无法查询而被阻塞,这种情况下,并发能力就相当的差。
而“快照读”就可以完成高并发的查询,不过,“读提交”只能避免
脏读
,并不能避免“不可重复读”(插入INSERT不是更新UPDATE)和“幻读”。
REPEATABLE READ(可重复读)(mysql默认的隔离级别)
普通的查询同样是使用的“快照读”,但是,和“读提交”不同的是,当事务启动时,就不允许进行“修改操作(Update)”了,而“不可重复读”恰恰是因为两次读取之间进行了数据的修改,因此,“可重复读”能够有效的避免不可重复读
,但却避免不了“幻读”,因为幻读是由于“插入或者删除操作(INSERT or DELETE)”而产生的,而不是更新(UPDATE)。
SERIALIZABLE(可串行化)
这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。由于他大量加上锁,导致大量的请求超时,因此性能会比较底下,再特别需要数据一致性且并发量不需要那么大的时候才可能考虑这个隔离级别。