事务隔离级别概念,事例以及分析.

ANSI/ISO SQL92 标准定义了一些数据库操做的隔离级别:
l   未提交读( read uncommitted
l   提交读( read committed
l   重复读( repeatable read
l   序列化( serializable
      也就是隔离级别,0,1,2,3。 ANSI/ISO SQL92 标准有很详细的说明,但是这个说明详细是详细,就是看不明白。今天经高人指点,茅厕顿开。
      隔离级别0与事务无关,而且不加锁,也就是说例如select * from t1,系统扫描过和读取的每一行都不加锁。
      隔离级别1与事务无关,只对正在取数的行加锁,取完数立刻开锁,也就是说,begin tran 而后select * from t1即便没有commit,锁也会自动打开。
      隔离级别2与事务有关,对扫描过的地方加锁。例如,select * from t1,系统从第1行开始扫描,扫描到第5行的时候,1到5行都处于锁定状态,直到commit,这些锁才解开。
      隔离级别3与事务有关,对全表加锁。

from:  http://marasuzifk.blog.51cto.com/24580/59591程序员

事务的四个属性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。sql

1.原子性(Atomic)
    最重要的原则,也是最容易理解的原则。被事务管理的全部方法,要么一块儿被提交,要么一块儿回滚。数据库

2.一致性(Consistency)
    事务在系统完整性中实施一致性,若是事务成功地完成,那么系统中全部变化将正确地应用,系统处于新有效状态。若是在事务中出现错误,那么系统中的全部变化将自动地回滚,系统返回到原始状态。并发

3.隔离性(Isolation)
    在隔离状态执行事务,使它们好像是系统在给定时间内执行的惟一操做。若是有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操做间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。重要的是,在隔离状态执行事务,系统的状态有多是不一致的,在结束事务前,应确保系统处于一致状态。可是在每一个单独的事务中,系统的状态可能会发生变化。若是事务不是在隔离状态运行,它就可能从系统中访问数据,而系统可能处于不一致状态。经过提供事务隔离,能够阻止这类事件的发生。oracle

4.持久性(Durability)
    持久性意味着一旦事务执行成功,在系统中产生的全部变化将是永久的。应该存在一些检查点防止在系统失败时丢失信息。甚至硬件自己失败,系统的状态仍能经过在日志中记录事务完成的任务进行重建。

数据库锁概念:
    在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其余的事务不能对它读取和修改。加了共享锁的数据对象能够被其余事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。
    从程序员的角度看,锁分为如下两种类型: 
    1.乐观锁(Optimistic Lock) 
    乐观锁假定在处理数据时,不须要在应用程序的代码中作任何事情就能够直接在记录上加锁、即彻底依靠数据库来管理锁的工做。通常状况下,当执行事务处理时SQL Server会自动对事务处理范围内更新到的表作锁定。 
    2.悲观锁(Pessimistic Lock) 
    悲观锁对数据库系统的自动管理不感冒,须要程序员直接管理数据或对象上的加锁处理,并负责获取、共享和放弃正在使用的数据上的任何锁。函数

事务隔离级别
    一个事务必须与其它事务进行隔离的程度。较低的隔离级别能够增长并发,但代价是下降数据的正确性。相反,较高的隔离级别能够确保数据的正确性,但可能对并发产生负面影响。

数据库并发操做存在的异常状况:
1. 更新丢失(Lost update):两个事务都同时更新一行数据可是第二个事务却中途失败退出致使对数据两个修改都失效了这是系统没有执行任何锁操做所以并发事务并无被隔离开来sqlserver

2. 脏读取(Dirty Reads):一个事务开始读取了某行数据可是另一个事务已经更新了此数据但没有可以及时提交。这是至关危险极可能全部操做都被回滚测试

3. 不可重复读取(Non-repeatable Reads):一个事务对同一行数据重复读取两次可是却获得了不一样结果。例如在两次读取中途有另一个事务对该行数据进行了修改并提交atom

4. 两次更新问题(Second lost updates problem):没法重复读取特例,有两个并发事务同时读取同一行数据而后其中一个对它进行修改提交而另外一个也进行了修改提交这就会形成第一次写操做失效spa

5. 幻读(Phantom Reads):也称为幻像(幻影)。事务在操做过程当中进行两次查询,第二次查询结果包含了第一次查询中未出现的数据(这里并不要求两次查询SQL语句相同)这是由于在两次查询过程当中有另一个事务插入数据形成的

为了不上面出现几种状况在标准SQL规范中定义了4个事务隔离级别,不一样隔离级别对事务处理不一样 。

1.未受权读取(Read Uncommitted):也称未提交读。容许脏读取但不容许更新丢失,若是一个事务已经开始写数据则另一个数据则不容许同时进行写操做但容许其余事务读此行数据。该隔离级别能够经过“排他写锁”实现。事务隔离的最低级别,仅可保证不读取物理损坏的数据。与READ COMMITTED 隔离级相反,它容许读取已经被其它用户修改但还没有提交肯定的数据。

2. 受权读取(Read Committed):也称提交读。容许不可重复读取但不容许脏读取。这能够经过“瞬间共享读锁”和“排他写锁”实现,读取数据的事务容许其余事务继续访问该行数据,可是未提交写事务将会禁止其余事务访问该行。SQL Server 默认的级别。在此隔离级下,SELECT 命令不会返回还没有提交(Committed) 的数据,也不能返回脏数据。

3. 可重复读取(Repeatable Read):禁止不可重复读取和脏读取。可是有时可能出现幻影数据,这能够经过“共享读锁”和“排他写锁”实现,读取数据事务将会禁止写事务(但容许读事务),写事务则禁止任何其余事务。在此隔离级下,用SELECT 命令读取的数据在整个命令执行过程当中不会被更改。此选项会影响系统的效能,非必要状况最好不用此隔离级。

4. 串行(Serializable):也称可串行读。提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。若是仅仅经过“行级锁”是没法实现事务序列化的,必须经过其余机制保证新插入的数据不会被刚执行查询操做事务访问到。事务隔离的最高级别,事务之间彻底隔离。若是事务在可串行读隔离级别上运行,则能够保证任何并发重叠事务均是串行的。

隔离级别 更新丢失 脏读取 重复读取 幻读
未受权读取 N Y Y Y
受权读取 N N Y Y
可重复读取 N N N Y
串行 N N N

N

-------------

本示例文档演示SQL SERVER,ORACLE下不一样事务隔离级别的区别,以及两种数据库自己的特色
  为了模拟并发环境,SQL SERVER在SMO程序中打开两个查询窗口便可。oracle能够用两个sql *plus程序链接到相同数据库来模拟
  SQL SERVER、ORACLE中两个并发用户用事务1,事务2简称。
  全部测试例子,都以最初测试表脚本运行后状态为基准。
  在下列例子中,set transaction isolation level语句会改变会话的隔离级别,直到会话结束。故测试完毕须要改回默认级别。
  最后,但并非最不重要。如下的演示和相关解释,都是基于易于理解的原则来的,实际的状况可能更复杂,但对开发人员来讲,理解如此程度的简化模型已经足够了。

 

测试表脚本:
SQL SERVER
CREATE TABLE [Customer](
 [CustID] [int] NOT NULL,
 [Fname] [nvarchar](20),
 [Lname] [nvarchar](20),
 [Address] [nvarchar](50),
 [City] [nvarchar](20),
 [State] [nchar](2) DEFAULT ('CA'),
 [Zip] [nchar](5) NOT NULL,
 [Phone] [nchar](10)
)
insert into customer values(1, 'Gary', 'Mckee', '111 Main', 'Palm Springs', 'CA', 94312, 7605551212)
insert into customer values(2, 'Tom', 'Smith', '609 Geogia', 'Fresno' 'JP', 33045, 5105551212)
insert into customer values(3, 'Jams', 'bond', 'ST Geogie 21', 'Washington', 'NY', 20331, 4405551864)

ORACLE
CREATE TABLE Customer(
 CustID int NOT NULL,
 Fname nvarchar2(20),
 Lname nvarchar2(20),
 Address nvarchar2(50),
 City nvarchar2(20),
 State nchar(2) DEFAULT 'CA',
 Zip nchar(5) NOT NULL,
 Phone nchar(10)
);
insert into customer values(1, 'Gary', 'Mckee', '111 Main', 'Palm Springs', 'CA', 94312, 7605551212);
insert into customer values(2, 'Tom', 'Smith', '609 Geogia', 'Fresno', 'JP', 33045, 5105551212);
insert into customer values(3, 'Jams', 'bond', 'ST Geogie 21', 'Washington', 'NY', 20331, 4405551864);

 

1. Sqlserver与oracle单条语句处理对比
SQL SERVER单条语句默认自动提交,即单条语句自动做为一个事务处理;而oracle的原则是尽可能延后提交,除非遇到显式提交命令或者DDL语句。
SQL SERVER
打开事务1:
运行:select * from customer
能够看到表有3条记录
运行:insert into customer values(4, 'Hello', 'world', 'paradise road 01', 'heaven', 'XY', 00001, 1234564321)
转到事务2:
运行:select * from customer
能够看到事务1中刚插入的custid为4的记录。

ORACLE
打开事务1,运行:
select * from customer;
能够看到表有3条记录,运行:
insert into customer values(4, 'Hello', 'world', 'paradise road 01', 'heaven', 'XY', 00001, 1234564321);
转到事务2,运行:
select * from customer;
能看到的仍是3条记录,事务1中刚插入的一条记录未自动提交,看不到。
转到事务1,运行:
commit;
转到事务2,运行:
select * from customer;
如今能看到4条记录了。


2. 丢失更新
Sqlserver彻底兼容ANSI 92标准定义的4个隔离级别。它的默认隔离级别是提交读(read committed),在该级别下,可能会有丢失更新的问题。Oracle的默认情形也同样。故再也不重复。
SQL SERVER
打开事务1运行:
set transaction isolation level read committed
begin tran
select * from customer  --看到3条记录
如今切换到事务2,此时事务1还未结束。在事务2中运行:
set transaction isolation level read committed
begin tran
select * from customer  --看到3条记录,和事务1中相同
如今假设事务1事务继续运行,修改数据并提交:
update customer set state = 'TK' where CustID = 3
commit
回到事务2,事务2根据先前查询到的结果修改数据:
update customer set Zip = 99999 where state = 'NY'
commit
结果由于事务1已经修改了事务2的where条件数据,事务2未成功修改数据(其实准确的说应该算是幻象读引发的更新失败。不过若知足条件的记录数多的话,事务2的update可能更新比预期的数量少的记录数,也可算"丢失"了部分本应完成的更新。我的认为只要明白实际上发生了什么便可,没必要过度追究字眼)。丢失更新还可能有别的情形,好比事务2也是
update customer set state = 'KO' where CustID = 3
两个事务都结束后,事务2的结果反映到数据库中,但事务1的更新丢失了,事务2也不知道本身覆盖了事务1的更新。


3.脏读演示
sqlserver的默认隔离级别是提交读(read committed),当手工将其改成未提交读时,事务能够读取其它事务没提交的数据;oracle因为自身特殊实现机制,能够理解为自身基础的隔离级别就是可重复读(与ANSI标准仍是有区别的,后面例子会说明)。
SQL SERVER
打开事务1,运行:
begin tran
select * from customer
 update customer set state = 'TN' where CustID = 3
转到事务2,运行:
set transaction isolation level read uncommitted
begin tran
select * from customer
此时看到的数据是事务1已经更新但还未提交的(3号记录state值TN)。而若是事务1发觉数据处理有误,转到事务1,进行回滚:
 Rollback
此时事务2如根据刚读取的数据进一步处理,会形成错误。它读取的数据并未更新到数据库,是"脏"的。

ORACLE
ANSI定义未提交读(read uncommitted)级别本意不是为了故意引入错误,而是提供一种可能的最大并发程度级别,即一个事务的数据更新不影响其它事务的读取。Oracle从内核层面实现了更新数据不阻塞读。能够说它提供未提交读级别的兼容,但没有脏读问题。(详情参考对应PPT文档)故oracle没有手工设置read uncommitted级别的语句。


4.不可重复读
Sql server的默认级别没有脏读问题,但存在不可重复读问题。Oracle默认级别也是提交读,不过它由于自身特殊机制,在语句一级不存在不可重复读问题。也就是说当运行时间较长的查询时,查询结果是与查询开始时刻一致的(即便查询过程当中其它事务修改了要查询的数据),而SQL SERVER就存在问题(sql server 2005新特性提供了可选的语句一级一致性支持,叫作行版本机制,实际上能够说是照着oracle的多版原本的,大致原理差很少)。
因为语句一级的事务一致性难以演示,下面例子是事务一级,提交读隔离级别下发生的不可重复读现象:
SQL SERVER
打开事务1,运行:
set transaction isolation level read committed
begin tran
select * from customer where State = 'CA'
能够获得1条记录,这个时候事务2中运行:
set transaction isolation level read committed
begin tran
update Customer set state = 'JP' where state = 'CA'
commit
事务2插入一条记录并提交。回到事务1,事务1继续运行,此时它再次相同的查询,并借此做进一步修改,却发现读取到的数据发生了变化。
select * from customer where State = 'CA'
--2次读取不一致,以后的数据处理应该取消。不然不正确
update Customer set city = 'garden' where state = 'CA'
commit
读取未能得到记录。也就是说在同一事务中两次相同的查询得到了不一样的结果,产生读取不可重复现象。

ORACLE
尽管oracle在默认隔离级别下提供了语句级的事务读一致性,但在事务级仍然是会出现不可重复读现象。和sql server同样,故再也不重复。


5.幻像读
当sqlserver的隔离级别设置为可重复读(repeatable read),能够解决上面例子出现的问题。其内部是经过事务期间保持读锁来实现的。
SQL SERVER
开始事务1,修改事务级别为可重复读,执行:
set transaction isolation level repeatable read
begin tran
select * from customer where State = 'CA'
和上例同样获得1条记录,这个时候事务2中运行:
set transaction isolation level repeatable read
begin tran
update Customer set state = 'JP' where state = 'CA'
commit
会发现事务2一直等待,并不结束。返回事务1,运行:
select * from customer where State = 'CA'  --2次读取结果一致
update Customer set city = 'garden' where state = 'CA'
commit
事务2成功结束后,再返回事务1,发现事务1也完成了。经过锁机制阻塞其它事务的修改,保持了事务期间读取的一致性。然而,若是是插入数据,则仍是会出现问题:
开始事务1,修改事务级别为可重复读,执行:
set transaction isolation level repeatable read
begin tran
select * from customer where State = 'CA'
获得1条记录,这个时候事务2中运行:
set transaction isolation level repeatable read
begin tran
insert into customer values(4, 'hellow', 'world', 'paradise 001', 'garden', 'CA', 00000, 1119995555)
commit
发现事务2马上提交并正常结束了。返回事务1,运行:
select * from customer where State = 'CA'
会发现获得了2条记录。这种现象就叫作幻像读。

ORACLE
因为自身特殊的机制,oracle没有提供一致读隔离级别的选项,想要得到一致读的效果,实际上须要将事务提高到串行化等级,即serializable。


6.串行化级别不一样数据库实现
在这个级别,能够认为事务中的数据不管什么时候都是一致的,此级别使它显得好像没有其它用户在修改数据,数据库在事务开始时候被"冻结"(至少,对于本事务涉及的数据如此)。然而在不一样数据库中,其实现机制也不一样。
SQL SERVER
开始事务1,运行:
set transaction isolation level serializable
begin tran
select * from customer where State = 'CA'
会获得1条记录,这时事务2开始运行:
set transaction isolation level serializable
begin tran
insert into customer values(4, 'hellow', 'world', 'paradise 001', 'garden', 'CA', 00000, 1119995555)
commit
会发现事务2挂起,它在等待事务1结束。回到事务1,继续:
select * from customer where State = 'CA'
update Customer set city = 'garden' where state = 'CA'
commit
在片刻的等待之后,事务1获得相似以如下格式消息:
消息1205,级别13,状态56,第1 行
事务(进程ID 51)与另外一个进程被死锁在锁资源上,而且已被选做死锁牺牲品。请从新运行该事务。
而事务2更新了数据并正常结束。这是由于两个事务都设置成了串行化级别,当遇到冲突时候,sql server根据必定的规则选择牺牲掉其中一个事务,来保证事务的串行性。上面的例子,若是将事务2的隔离级别改成提交读,那么事务2会等待事务1完成,以后本身正常完成(由于事务2没有串行需求,不会有死锁)。

ORACLE
在oracle中,经过多版本,能够在必定程度上避免死锁。
开始事务1,运行:
set transaction isolation level serializable;
select * from customer where State = 'CA'; --set tran语句隐式开始事务
获得1条记录,而后事务2开始运行:
set transaction isolation level serializable;
insert into customer values(4, 'hellow', 'world', 'paradise 001', 'garden', 'CA', 00000, 1119995555);
commit;
能够发现事务2马上完成,没有阻塞。回到事务1继续:
select * from customer where State = 'CA';
update Customer set city = 'garden' where state = 'CA';
commit;
事务1中的第二次查询和事务开始时刻一致,就好像事务2已经完成的提交不存在。事务最终正常更新完毕,并保持了"事务开始"时刻的数据一致性。
然而,若是事务1,2修改一样的数据行,也会有错误,
开始事务1,运行:
set transaction isolation level serializable;
select * from customer where State = 'CA'; --set tran语句隐式开始事务
获得1条记录,而后事务2开始运行:
set transaction isolation level serializable;
update customer set state = 'KO' where state = 'CA';
commit;
能够发现事务2马上完成,没有阻塞。回到事务1继续:
select * from customer where State = 'CA';
update Customer set city = 'garden' where state = 'CA';
commit;
出现错误信息:
第 1 行出现错误:
ORA-08177: 没法连续访问此事务处理
总的来讲,oracle利用多版本的方式实现串行化级别更少形成死锁,除非两个事务修改了相同的数据行,通常也不会形成冲突。

 

7.不一样隔离级别的相互影响
前面的例子基本都是两个相同隔离级别事务的状况。若是不一样隔离级别的事务发生冲突,会有什么不一样吗?实际上,对于一个事务来讲,其它事务的隔离级别对它来讲是未知的,更进一步,甚至数据库中有没有其它事务,有多少事务也不知道。影响事务访问数据就两方面因素:该事务自身的隔离级别,该事务要访问的数据上面锁的状态。
SQL SERVER
开始事务1,运行:
set transaction isolation level serializable
begin tran
select * from customer where State = 'CA'
事务1的查询得到1条记录,转到事务2,运行:
set transaction isolation level read uncommitted
begin tran
select * from customer
事务2查询得到3条记录,回到事务1,运行:
update Customer set city = 'garden' where state = 'CA'
切换到事务2,运行:
select * from customer
update customer set state = 'KO' where state = 'CA'
commit;
由于事务2隔离级别为未提交读,所以事务1中刚做的修改能够马上从查询看到,即便事务1还未结束。进一步的update由于事务1对记录加了独占锁,所以事务2挂起。回到事务1将其提交:
Commit
事务1正常结束,独占锁释放,从而让事务2得以继续修改数据,并最终完成。

ORACLE
Oracle数据库的隔离级别设置语句只有read committed和serializable(read only暂不讨论),加上其特殊锁机制,不一样隔离级别事务间的影响除了上例(例6)中两个都为serializable的状况,其它均可视为互不阻塞。

 

8.页锁与行锁(限sql server)
Sql server的锁能够到行一级。然而它又存在自动的锁定扩大,锁定转换。所以存在一些意想不到的状况。下面是演示:
开始事务1,运行:
set transaction isolation level read committed
begin tran
select * from customer where State = 'CA'
update Customer set city = 'garden' where state = 'CA'
理论上来讲,在提交读级别下,上面的update语句只是在state值为CA的数据行上加了独占锁,表中其它数据应该能够被其它事务更新,然而,以下事务2开始:
set transaction isolation level read committed
begin tran
select * from customer
update customer set state = 'KO' where state = 'JP'
commit
发现事务2陷入阻塞状态。尽管它们更新的不是同一条记录。回到事务1,运行:
Commit
事务1结束后事务2才继续运行至结束。
若是咱们在表上加入索引,以下:
CREATE NONCLUSTERED INDEX [idx_state] ON [dbo].[Customer] ( [State])
再重复上面的步骤,会发现阻塞再也不存在。
PS:这种现象应该和数据库默认加锁参数/机制有关,应该能够调整,但目前手中没有进一步资料。故仅罗列了现象。

ORACLE
Oracle在数据一级只有一种数据行上的锁,所以不存在sql server中这些问题。

 

9.Set transaction语句的做用周期
前面全部的例子,都是在会话窗口中进行的演示。一旦使用了set transaction语句,会影响整个会话。除非再显式改变隔离级别,不然将保持到会话结束。例如:
开始事务1,假设会话一开始处于SQL SERVER的默认隔离级别(read committed):
begin tran
select * from customer where State = 'CA'
select * from sys.dm_tran_locks
系统视图sys.dm_tran_locks能够查看当前的加锁状况,到目前位置,只有数据库级的锁。继续运行:
set transaction isolation level repeatable read
select * from customer where State = 'CA'
select * from sys.dm_tran_locks
commit
接下来的语句改变了隔离级别到可重复读,接下来的查询,会看到行级锁的记录。在上面事务提交后,运行:
begin tran
select * from customer where State = 'CA'
select * from sys.dm_tran_locks
commit
仍然会从视图sys.dm_tran_locks看到行级锁记录。整个会话期间都受到影响。

可是,若是调用存储过程,函数,则过程/函数中事务隔离级别的改变并不会对调用环境形成影响。能够经过如下例子说明,首先,建立一个存储过程脚本:
CREATE PROCEDURE [dbo].[test_tran_level]
AS
BEGIN
 BEGIN TRAN
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
 SELECT * FROM CUSTOMER
 UPDATE CUSTOMER SET STATE = 'SS' WHERE CustID = 3
 SELECT * FROM sys.dm_tran_locks
 COMMIT
END
而后,在会话窗口调用该过程,会话窗口当前隔离级别为默认的提交读:
Exec test_tran_level
运行的结果能够看到读取锁信息,再在会话中运行:
begin tran
select * from customer where State = 'CA'
select * from sys.dm_tran_locks
commit
视图sys.dm_tran_locks并未有读锁的记录,说明事务隔离级别仍然是提交读。

问题

 

咱们看到,当执行不一样的隔离级别时,可能会发生各类各样不一样的问题。下面对它们进行总结并举例说明。

 

幻读

 

幻读发生在当两个彻底相同的查询执行时,第二次查询所返回的结果集跟第一个查询不相同。

 

发生的状况:没有范围锁。

 

例子:

 

 

事务1 事务2

SELECT * FROM users

WHERE age BETWEEN 10 AND 30;

 
  INSERT INTO users VALUES (3, 'Bob', 27);
SELECT * FROM users 
WHERE age BETWEEN 10 AND 30;
 

 

 

如何避免:实行序列化隔离模式,在任何一个低级别的隔离中均可能会发生。

 

不可重复读

在基于锁的并行控制方法中,若是在执行select时不添加读锁,就会发生不可重复读问题。

在多版本并行控制机制中,当一个遇到提交冲突的事务须要回退但却被释放时,会发生不可重复读问题。

 

事务1 事务2
SELECT * FROM users WHERE id = 1;

 

 

UPDATE users SET age = 21
WHERE id = 1;
COMMIT;

/* in multiversion concurrency*/
control, or lock-based

READ COMMITTED *

SELECT * FROM users 
WHERE id = 1;
 
 

COMMIT; /* lock-based REPEATABLE READ */

 

 

在上面这个例子中,事务2提交成功,它所作的修改已经可见。然而,事务1已经读取了一个其它的值。在序列化和可重复读的隔离级别中,数据库管理系统会返回旧值,即在被事务2修改以前的值。在提交读和未提交读隔离级别下,可能会返回被更新的值,这就是“不可重复读”。

 

有两个策略能够防止这个问题的发生:

1. 推迟事务2的执行,直至事务1提交或者回退。这种策略在使用锁时应用。

2. 而在多版本并行控制中,事务2能够被先提交。而事务1,继续执行在旧版本的数据上。当事务1终于尝试提交时,数据库会检验它的结果是否和事务一、事务2顺序执行时同样。若是是,则事务1提交成功。若是不是,事务1会被回退。

 

脏读

脏读发生在一个事务A读取了被另外一个事务B修改,可是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读相似,可是第二个事务不须要执行提交。 

 

事务1 事务2
SELECT * FROM users WHERE id = 1;   
  UPDATE users SET age = 21
WHERE id = 1;
SELECT FROM users WHERE id = 1;  
  COMMIT; /* lock-based DIRTY READ */
相关文章
相关标签/搜索