首先介绍事物的四大特性(ACID):
原子性:事务中的最小执行单位,要么全部执行,要么全部失败(回滚);
一致性: 执行事务前后,保证数据一致,多个事务对同一个数据读取的结果是相同的;
例如转账案例 假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。
隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性:一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
脏读,幻读,不可重复读,丢失修改
脏读:事务A查询数据后进行了一次修改且未提交,而事务B这个时候去查询,然后使用了这个数据,因为这个数据还没有被事务A 提交到数据库中,所以事务B的得到数据就是脏数据,对脏数据进行操作可能是不正确的。
不可重复读: 事务A访问了两次数据,但是这访问第二次之间事务B进行一次并进行了修改,导致事务A访问第二次的时候得到的数据与第一次不同,导致一个事务访问两次数据得到的数据不相同。因此叫做不可重复读。
幻读: 与不可重复读都点相似,只是这次是事务B在事务A访问第二次的之前做了一个新增,导致事务A第二次读取的时候发现了多的记录,这就是幻读。
丢失修改:事务A访问该数据,事务B也访问该数据,事务A修改了该数据,事务B也修改了该数据,这样导致事务A的修改被丢失,因此称为丢失修改;
不可重复度和幻读区别:
不可重复读主要是修改操作,幻读的主要在于新增或者删除。
幻读主要在于数据的条数变了,而不可重复读主要在于数据内容变了。
当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读 (non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有 了“隔离级别”的概念。
注意隔离级别越高,效率越低
SQL 标准的事务隔离级(参考高性能MySQL第三版)
读未提交(read uncommitted):事务可以读取未提交的数据,这也被称为脏读( Dirty Read)。这个级别会导致 很多问题,从性能上来说, 读未提交不会比其他的级别好太多,但却缺乏 其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。最低的隔离级别
读已提交(READ-COMMITTED):大多数数据库默认隔离级别都是这个,但是MySQL不是,一个事务开始的时候到提交所做的操作对其他事务是不可见的。避免了脏读,但是仍然会出现幻读和不可重复读 MySQL默认隔离级别。
可重复读(REPEATABLE-READ):保证了同一个事务多次读取同样的记录结果是一致的。可以阻止脏读和不可重复读,但幻读仍有可能发生。
可串行化(SERIALIZABLE):最高的隔离级别,完全服从ACID的隔离级别。强制事务串行执行,避免了幻读,脏读和不可重复读。他会在读取的时候给每一个行加锁,所以可能导致大量的超时和锁争用的情况,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下才考虑的级别。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read uncommitted) | √ | √ | √ |
读已提交(READ-COMMITTED) | × | √ | √ |
可重复读 (REPEATABLE-READ) | × | × | √ |
可串行化 (SERIALIZABLE) | × | × | × |
这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 REPEATABLE-READ(可重读)事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的SERIALIZABLE(可串行化)隔离级别。