SQL有四种隔离级别,分别为未提交读(read uncommited)、提交读(read commited)、可重复读(repeatable read)、可串行化(serializable)。
一、未提交读
在未提交读中,事务中的修改,即使没有提交, 对其他事务也都是可见的。这会导致未提交的事务对其他事务也是可见的,这种情况被称为脏读(dirty read)。如果使用未提交读隔离级别,在工作中可能会发生这样的情况:当你在使用函数求本月的资产、负债和所有者权益时(在会计平衡公式中,资产=负债+所有者权益),你发现等式两边不平。如果会计的水平没有问题的话,那么大概率是读到了写到一半仍未提交的事务。
二、提交读
提交读是大多数数据库的默认隔离级别。在提交读中,一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读(nonrepeatable read),因为两次执行同样的查询,可能会得到不一样的结果。不可重复读经常与幻读(phantom read)混淆,经过我大量阅读其他人的博文学习之后,我也比较认可的一个观点是幻读可以被认为是不可重复读的其中一种特殊情况。“不可重复读”和“幻读”都是读的过程中数据前后不一致,只是前者侧重于删除修改,后者侧重于新增。sql设计者把它们区分开来的原因是对这两种情况的解决方案完全不同,解决幻读的代价比不可重复读要大得多,因为我们没办法用锁保证安全。如果使用提交读,在工作中可能会遇到这样的情况(不可重复读):你在同一次事务中查询并计算张三本月平均每天的bug个数,然后计算张三本月bug总数,你发现第一次查询张三平均每天bug个数1个,但是第二次查询本月bug总数229个,这就对不上了啊。原因是在你查询的时候,你的同事修改表把第30天的bug个数改成了200个。这样就碰到了不可重复读的情况。
三、可重复读
可重复读是MySQL的默认事务隔离级别,解决了脏读的问题。这个级别保证了在同一个事务中多次读取同样记录的结果是一致的(指已存在的行数据不会被改变)。但是可重复读隔离级别还是无法解决幻读的问题。举一个可重复读隔离级别下可能会碰到的情况(幻读):还是计算bug的例子,你在计算所有人bug总数的时候,第一次查询算出总数为200个,第二次查询计算出总数为400个。这可能是因为有同事新插入了一个bug大王的数据200个bug。因为新插入的数据在插入前是不存在的,没法用锁保证安全,所以被单独拿出来需要特殊的解决方案。
四、可串行化
可串行化是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。serializable会在每一行上都加锁,保证数据的安全问题。如果需要极高的安全性且可以接受没有并发的情况,可以使用这个事务隔离级别。这个级别挺安全的,没有例子。