首先用通俗的语言介绍以下事务的特性(ACID):

       原子性(Atomicity):原子性是指一个事务中的操作,要么全部成功,要么全部失败,如果失败,就回滚到事务开始前的状态。

       一致性(Consistency):一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。那转账举栗子,A账户和B账户之间相互转账,无论如何操作,A、B账户的总金额都必须是不变的。

       隔离性(Isolation):隔离性是当多个用户 并发的 访问数据库时,如果操作同一张表,数据库则为每一个用户都开启一个事务,且事务之间互不干扰,也就是说事务之间的并发是隔离的。再举个栗子,现有两个并发的事务T1和T2,T1要么在T2开始前执行,要么在T2结束后执行,如果T1先执行,那T2就在T1结束后在执行。关于数据的隔离性级别,将在后文讲到。

       持久性(Durability):持久性就是指如果事务一旦被提交,数据库中数据的改变就是永久性的,即使断电或者宕机的情况下,也不会丢失提交的事务操作。

什么是事务的隔离性(Isolation)呢?

       隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离。

如果不考虑隔离性,会发生什么事呢?

1.脏读(Dirty Read):

       脏读是指一个事务在处理数据的过程中,读取到另一个未提交事务的数据。

      脏读最大的问题就是可能读到不存在的数据。比如下图中,事务B的更新数据被事务A读取,但是事务B回滚了,数据全部还原,也就是说事务A刚刚读到的数据并没有存在于数据库中。

 2.不可重复读(nonrepeatable read):

       不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。具体如下图,Trans B在Trans A两次读取数据之间对数据进行修改,导致Trans A两次读取结果不一致。

       不可重复读和脏读的区别是,脏读读取到的是一个未提交的数据,而不可重复读读取到的是另一个事务提交的数据。

       而不可重复读在一些情况也并不影响数据的正确性,比如需要多次查询的数据也是要以最后一次查询到的数据为主。

3.幻读(Phantom read)

       幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

       幻读不可重复读都是读取了另一事务已经提交的数据(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

       不可重复读和幻读是初学者不易分清的概念,总的来说,解决不可重复读的方法是 锁行,解决幻读的方式是 锁表

四种隔离级别解决了上述问题

1.未提交读(Read uncommitted):

       这种事务隔离级别下,select语句不加锁,事务中修改的数据,即使没有提交,对其他事务也都是可见的。

       此时,可能读取到不一致的数据,即“读脏 ”。这是并发最高,一致性最差的隔离级别。

2.提交读(Read committed):

       一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。

       大多数数据库系统的默认隔离级别都是提交读(但Mysql不是)。提交读满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。可避免脏读,无法避免不可重复读发生。

       因为两次执行同样的查询,可能会得到不一样的结果,这个级别有时候也叫做不可重复读(nonrepeatable read)。

3.可重复读(Repeatable read):

       该级别保证了在同一个事务中多次读取同样记录的结果是一致的,事务中未提交的数据对其他事务是不可见的,解决 脏读 、不可重复读 的问题,是MySql默认隔离级别。

4.串行化(Serializable ):

       可串行化是最高的隔离级别。它通过强制事务串行执行,避免了脏读、不可重复读、幻读的问题。

       简单来说,可串行化会在读取的每一行数据上都加上锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑用该级别。

       以上四种隔离级别最高的是 Serializable 级别,最低的是 Read uncommitted 级别,当然级别越高,执行效率就越低。像 Serializable 这样的级别,就是以 锁表 的方式,使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。SQL Server默认的隔离级别为rcommitted,MySQL默认的隔离级别为Repeatable read, Oracle默认隔离级别为Read committed。

  SQL Server和MySQL数据库支持上面四种隔离级别,而 Oracle数据库只支持Serializable (串行化) 级别和 Read committed (读已提交) 这两种级别。  

本文转自:https://blog.csdn.net/u010960184/article/details/82557978,并进行部分修改

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐