数据库事务及隔离级别

摘要:现在的数据库系统都是多用户系统,允许不同用户同时操作相同的数据,为此要求数据库系统要有并发处理能力。一旦执行并发处理,就会出现数据的不一致。而利用事务,可以让数据库系统在并发访问时尽量避免出现数据不一致的问题。利用事务可以让数据库的并访问性能两方面取得平衡。

一、事务的特性

数据库事务由4个最基本的特性,即原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称“ACID”。

(1)   原子性

一个事务由一个个单元组成,每个逻辑单元可以被看作一个操作。如果有一个操作失败,则整个事务中的所有操作都要取消,包括已经成功执行的操作,并回到事务执行前的状态。

(2)   一致性

事务所操作的数据在事务执行前后必须在逻辑上一致,如转账操作。A账号原有10000元,B账号原有10000元,两个账号的金额总数为20000元。A账号转10000元到B账号中,如果事务完成,A账号中有0元,B账号中有20000元;如果事务取消,A账号有10000元,B账号有10000元。事务要保证转账无论是否成功,两个账号的金额总数仍为20000元,不能出现其他情况。

(3)   隔离性

当前事务与其他为完成的事务之间相互隔离,在数据库事务中可以设置事务的不同隔离级别。在多人使用的环境下,每个使用者可能处理自己的事务,事务之间必须互补干扰。使用者不会意识到其他使用者正在处理事务,如同只有自己在操作一样。

(4)   持久性

对数据库中的数据修改都要写到硬盘中,如果在操作过程中发生断电或系统错误等故障,数据库要保证未结束的事务在下次数据库启动后被全部撤销;结束的事务把修改后的结果写入到磁盘中,从而保证事务对数据修改的持久化。

二、并发访问数据可能引发的问题

不同事务同时操作相同的数据,如果没有合理控制,会在并发操作的数据上产生不一致的问题,即更新丢失(lose update)、脏读(dirty read)、不可重复读(non-repeatable read)、第二类丢失更新(second lost update)和幻读(phantom)

(1)   丢失数据修改

当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生更新问题。每个事务都不知道其他事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。

例如:两个编辑人员制作了同一文档的电子复本,每个编辑人员独立地更改其复本,然后保存更改后的复本,这样就覆盖了原始文档。最后保存其更改复本的编辑人员覆盖了第一个编辑人员所做的更改。如果在第一个编辑人员完成之后第二个编辑人员才能进行更改,则可以避免该问题。

(2)   读“脏”数据

读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销,而此时T1把已经修改过的数据又恢复原值,T2读到的数据与数据库的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。

例如:一个编辑人员正在更改电子文档。在更改的过程中,另一个编辑人员复制了该文档并将其分发给预期的用户。此后,第一个编辑人员认为目前所做的更改时错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应认为从未存在过。如果在第一个编辑人员确定最终更改前任何人都不能读取更改的文档,则可以避免该问题。

(3)   不可重复读

不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取的结果。具体来讲,不可重复读包括三种情况:

  • 事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读取该数据时,得到与前一次不同的值。
  • 事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神秘地消失了。
  • 事务T1按一定条件从数据库中读取某些数据记录后,事务T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。

后两种不可重复读有时也称为幻读(Phantom Row)现象。

       小结:产生上述三类数据不一致性的主要原因是并发操作破坏了事务的隔离性。并发控制就是要用正确的方式调度并发操作,使一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性。另一方面,对数据库的应用有时允许某些不一致性,例如有些统计工作涉及数据量很大,读到一些“脏”数据对统计精度没什么影响,这是可以降低对一致性的要求以减少系统开销。

三、事务的隔离级别

(1)未授权读取(Read Uncommitted)

       一个事务可以读取另一个事务已更新且尚未提交的数据,但在另一个事务提交前不允许其他事务写入。这种隔离级别可能出现脏读,但是不可能出现更新丢失。其读取数据出错的几率高,多数的应用系统不会采用这种隔离层级。

(2)授权读取(Read Committed)

比read uncommitted更严格一些,某个事务尽可(不可修改或者删除)读取另一个事务已经提交的更新数据,不可以读取尚未提交的更新数据。这种隔离级别不可能出现脏读,但可能出现不可重复读和幻读。

这是oracle的默认隔离级别,设置为这种隔离级别的事务只能读取其他事务已经提交的更新数据;否则发生等待。其他事务可以修改这个事务中被读取(未被更新)的记录,而不必等待事务结束。

(3)可重复读取(Repeatable Read)

比read committed更严格,一个事务已读取的数据不允许其他事务写入。该级别不可能出现不可重复读,但可能出现幻读。

(4)序列化(Serializable)

最严格的事务隔离级别,要求所有事务序列化执行,不能并发执行。该级别不可能出现幻读。

还有一种Read only 它不是SQL92的标准,而是Oracle中所特有的事务隔离级别。该级别是Serializable的子集,这种隔离级别只允许事务执行查询操作,而不允许执行任何修改数据的操作。

使用这种事务时可以确保用户取得特定时间点的数据,如超市的收银系统需要每天在22:00时统计当前的销售情况,而不统计之后的销售情况。这种情况下可以使用该事务,尽管其他事务会提交,但当前的只读事务将不会读取新数据。从而确保取得特定时间点的数据。

事务隔离级别的选择

不同隔离级别可能发生的并发问题如下表:

隔离级别

更新丢失

脏读

不可重复读

幻读

Read Uncommitted

不可能

可能

可能

可能

Read committed

不可能

不可能

可能

可能

Repeatable Read

不可能

不可能

不可能

可能

Serializable

不可能

不可能

不可能

不可能

隔离级别越高,越能保证数据的一致性和完整性,但是对并发性能的影响也越大。ReadUncommitted级别出错的几率过高,Serializable级别效率过低,所以这两种级别在实际的应用系统中很少选用。Read Committed级别可以避免脏读,而且具有较好的并发性能。大部分应用程序应会选用该级别,这也是目前大多数数据库的默认级别。尽管它会导致不可重复读和虚读的问题,在可能出现这类问题的个别场合可以在应用程序中使用悲观锁(Pessimistic Locking)或乐观锁(Optimistic Locking)来控制。

Oracle中的事务隔离级别

Oracle不支持Read Uncommitted和Repeatable Read,只支持Read Committed(默认)和Serializable隔离级别。

在Oracle中设置事务隔离级别的语句如下所示:这是SQL92的标准语法,也适用其他数据库:

Set TransactionIsolation Level read committed


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值