数据库隔离级别不够时容易出现3种情况:
- 脏读:即事务A读取到了事务B未提交的数据。该数据可能不是最终数据而是中间变量,因此会导致事务A读取到错误的数据。
- 不可重复读:即事务A多次访问同一个数据,获得结果不相同。在访问间隔时,事务A访问数据被事务B修改,导致事务A多次读取到不一样的数据值。
- 幻读:即事务A在读取某些数据时,事务B通过插入或删除等方式对数据集进行了修改,导致事务A读取到了事务B执行后的结果。
数据库的四种隔离级别:
1. 可读取未提交(Read uncommitted)
写事务阻止其他写事务
可能存在的问题:脏读。读事务可能读取到非最终数据而导致错误。
2. 可读取已提交(Read committed)
写事务阻止其他读写事务
*SQL Server, Oracle 数据库的默认隔离级别
可能存在的问题:不可重复读。两次相同的读事务之间可能执行过写事务。
3. 可重复读(Repeatable read)
读事务阻止其他写事务
*MySQL数据库的默认隔离级别
可能存在的问题:幻读。阻止写事务将对已存在的数据表加锁,但是无法阻止还未存在的行,即INSERT
命令依旧会执行,造成两次读取行数不一。
4. 串行化(Serializable)
读事务加共享锁,写事务加排他锁
共享锁:可以查看但无法修改和删除数据,如 SELECT
语句。
排他锁:既能读数据,又能修改数据,如INSERT
、UPDATE
或DELETE
语句。
在数据库加共享锁后,其他事务可以再加共享锁,但无法加排他锁;
在数据库加排他锁后,后面的事务是无法在获得该数据库的任何锁。
MySQL的InnoDB引擎来说,对于INSERT
、UPDATE
或DELETE
等操作。会自动给涉及的数据加排他锁;对于一般的 SELECT
语句,InnoDB不会加任何锁,事务可以通过以下语句给显示加共享锁或排他锁。
共享锁:SELECT ... LOCK IN SHARE MODE
;
排他锁:SELECT ... FOR UPDATE
;