数据库常用的隔离级别
四大特性
任何支持事务的数据库,都必然具备四大特性ACID:
- 原子性(Atomicity):说的是一个事物内所有操作共同组成一个原子包,要么全部成功,要么全部失败。这是最基本的特性,保证了因为一些其他因素导致数据库异常,或者宕机。
- 一致性(Consistency):在基于原子性的前提下,保证双方数据的一致性;因为原子性保证的只是双方的操作是一致的,但在操作存在事务与时延;一致性得保证的只会有前状态和后状态,绝不会出现中间态。
- 隔离性(Isolation):基于原子性和一致性的前提下,事务的隔离,因为事务是可以有多个原子包的形式并发执行,但是,每个事物互不干扰。
- 持久性(Durability):当一个事务提交后,数据的状态则永远都改变。不能因为提交后服务器宕机,而导致提交失效。
只有确保以上四点的数据库,这样才能确保事务(Transaction)的正确性。
事务隔离
事务隔离就是指:多个并发的事务同时访问一个数据库时,一个事务不应该被另一个事务所干扰,每个并发的事务间要相互进行隔离。
没有事务隔离所产生的问题
- 脏读:A查询 B修改后未提交的的数据;当B回滚后,则A查询的数据是无效的;
- 不可重复读:A在第一次查询用户甲的信息,B将用户甲的信息修改并提交;A再次获取甲的信息,A两次获取的信息不同则称之为“不可重复读”;
- 幻读:类似不可重复读,A查询用户数量,当B新增或删除用户,A再次获取用户的数量不同;则称之为“幻读”。
PS:“不可重复读”与“幻读”区别在于,不可重复读强调的是数据信息的改变,而幻读强调数据数量上的改变。
事务隔离级别
为了防止以上情况所产生的脏读、不可重复读、幻读等情况,我们就需要根据实际情来设定数据的事务隔离级别;
- 读未提交(Read Uncommitted):最低级别,任何情况都无法保证。就是可以读到未提交的内容,在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。
- 读提交(Read Committed):可避免脏读的发生。就是只能读到已经提交了的内容。
- 可重复读(Repeated Read):可避免脏读、不可重复读的发生。当事务启动时,就不允许进行“修改操作(Update)”了,而“不可重复读”恰恰是因为两次读取之间进行了数据的修改,因此,“可重复读”能够有效的避免“不可重复读”,但却避免不了“幻读”,因为幻读是由于“插入或者删除操作(Insert or Delete)”而产生的。
- 串行化(Serializable):可避免脏读、不可重复读、幻读的发生。这是数据库最高的隔离级别,这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。这种级别下,“脏读”、“不可重复读”、“幻读”都可以被避免,但是执行效率奇差,性能开销也最大,所以基本没人会用。
以上四种隔离级别,串行化(Serializable) 的级别最高,读未提交(Read uncommitted) 的级别最低,级别越高,效率越低;
串行化(Serializable)就是以锁的方式使其他线程只能在锁外面等待;
MySQL支持上面四种隔离级别,默认的隔离级别是可重复读(Repeatable read);
Oracle数据库只支持 串行化(Serializable) 和 读已提交 (Read committed) ,默认是读已提交(Read committed);
总结
为什么会出现“脏读”? 因为“select”操作没有规矩。
为什么会出现“不可重复读”? 因为“update”操作没有规矩。
为什么会出现“幻读”? 因为“insert”和“delete”操作没有规矩。
“读未提(Read Uncommitted)”能预防啥? 啥都预防不了。
“读提交(Read Committed)”能预防啥? 使用“快照读(Snapshot Read)”,避免“脏读”,但是可能出现“不可重复读”和“幻读”。
“可重复读(Repeated Red)”能预防啥? 使用“快照读(Snapshot Read)”,锁住被读取记录,避免出现“脏读”、“不可重复读”,但是可能出现“幻读”。
“串行化(Serializable)”能预防啥? 排排坐,吃果果,有效避免“脏读”、“不可重复读”、“幻读”,不过效果谁用谁知道。