大纲
1.什么是事务?
2.事务的四大特性ACID
3.数据库的四种隔离级别
4.事务并发执行会出现的问题
1.什么是事务(Transaction)?
一组操作,要么全部执行成功,要么全部不执行。事务由一组操作组成,其中任一操作发生错误,则回滚之前成功的操作。
2.数据库事务的四大特性ACID
原子性(Atomicity):事务是一个不可分割的执行单元,事务包含的全部操作要么全部执行成功,要么全部失败回滚。也即成功则完全应用到数据库,失败则对数据库不产生任何变更。
一致性(Consistency):事务开始前和结束后,数据库的完整性约束(存储在数据库中的所有值都是正确的)没被破坏。
隔离性(Isolation):每个事务相互独立,互不干扰,一个事务无法看到另一个事务中的数据。
持久性(Durability):事务执行完成,其结果是持久化保存的。即使数据库发生崩溃,数据库恢复后事务提交的结果仍然存在(当然如果数据无法恢复的另说)。
3.数据库的四种隔离级别
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
Repeatable read (可重复读):可避免脏读、不可重复读的发生。
Read committed (读已提交):可避免脏读的发生。
Read uncommitted (读未提交):最低级别,任何情况都无法保证,可能产生脏读、不可重复读、幻读的现象。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);
在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
注意:设置数据库的隔离级别一定要是在开启事务之前!
4.事务并发执行会出现的问题
脏读:
指一个事务在处理过程中读取了另一个未提交的事务中的数据。
比如事务A执行向账户1转500块钱的操作,此时事务A未提交,另一个事务B来查询账户1的余额发现多了500块钱(此时已经出现了脏读)。如果事务A不提交,操作回滚,再来查询账务1中的余额就会发现钱并没有转。
不可重复读:
指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在两个查询间隔,被另一个事务修改并提交了。
例如:事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主,但在某些情况下就有可能发生问题。
幻读:
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体。