Chinaunix首页 | 论坛 | 博客

Ra

  • 博客访问: 6781
  • 博文数量: 6
  • 博客积分: 160
  • 博客等级: 入伍新兵
  • 技术积分: 65
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-13 09:05
文章分类
文章存档

2011年(1)

2009年(5)

我的朋友
最近访客

分类: 数据库开发技术

2009-05-04 10:17:36

数据的一致性与并发性
 
假设你有一个存货管理系统,用于跟踪许多仓库中的产品条目。 在系统运行时,你的应用程序必须要出一个存货估价报表。使用读提交(read committed)的事务隔离,会发生下面的一系列事件:
  1
、开始一个将要合计价值的读事务,从各个仓库收集条目;
  2
、这个读事务扫描Abilene仓库的所有记录;
  3
、另一个用户开始一个更新事物,从Abilene仓库移动1000金条到San Antonio仓库;
  4
、更新事务提交;
  5
、读事务读到San Antonio仓库的记录。这个读事务现在就把1000金条计算了两次, 一次在Abilene仓库,另一次在San Antonio仓库。
 
MSSQLServer中,通过给读事务使用Serializable(连续读)事务隔离很容易避免这个问题。 Serializable隔离模式保护你的事务在其生存期内不会看到由其他用户作出的改变。然而,要达到这种效果,MSSQLServer要么锁住整个表,要么在WHERE语句跨越的所有覆盖值的索引上放一系列锁 (引自Microsoft SQL Server 2000, Microsoft Press,799) 虽然这些锁比表锁限制少,但仍有很多本来不必要的行被禁止插入。考虑下面的SELECT语句:
  SELECT * FROM CUSTOMER WHERE CITY >= 'Charleston' AND CITY <= 'Los Alamos'
 
假设在CITY列的索引中覆盖的WHERE语句的范围是Abilene, Detroit, and San Francisco这些节点,那么这些节点都会被锁住。不幸的是,这将意味着你不能插入这样一列,它的值大于Abilene而小于Charleston,即使WHERE语句没有包含这一行,因为它在锁的覆盖范围内。同样的原因,你也不能插入其值大于Los Alamos而小于San Francisco的行(引自Microsoft SQL Server 2000, Microsoft Press,776 )
 
虽然数据的一致性达到了,但这也牺牲了并发性, 因为其他用户不能在行锁覆盖的行及表锁覆盖的表上插入和更新的记录。当分析和汇总大量的数据时
——
比如上面的例子,在读事务结束之前,其他用户的插入和更新会一直被阻塞。
 
IB/FB中,由于IB的版本引擎机制,这个问题根本就不存在。回到库存估价的例子中,下面是IB/FB的情况:
  1
、使用快照事务隔离机制,读事务开始;
  2
、读事务扫描Abilene仓库的记录;
  3
、另一个用户开始一个更新事务,从Abilene移动1000金条到San Francisco
  4
、更新事务发现一个更早的活动事务,于是为需要更新的记录创建新的版本;
  5
、更新事务提交;
  6
、读事务读到San Antonio中更新的记录。 读事务看到当前记录的版本是由一个在它之后开始的事务创建的,于是它往回扫描记录的版本,直到它发现一个在它开始时已经提交的版本,并读那个版本。
 
通过读那些只在读事务开始时已经提交的记录版本, 不用禁止记录的更新,IB/FB就能提供一个逻辑上一致的数据视图。
 
 
死锁
 
假如用户A执行一个SELECT语句读Parts表中的所有行。用户BSELECTParts表的所有行。两个用户都要获得各自所选数据的一个稳定一致的视图。用户A试图更新part=100的记录。用户B试图更新part=101的记录。
  MSSQLServer
会使用重复读或serializable事务隔离,这种情况将导致死锁,即使两个用户更新的是不同的行。怎么会呢?A在读记录时得到表上的一个共享锁。B也一样。当A更新part=100的记录时,必须得到这一行的排他锁,于是把他在表上的共享锁转换成意向排他锁。然而,意向排他锁和B的共享锁冲突,所以无法得到(引自Microsoft SQL Server 2000, Microsoft Press,799 )。同样,当B要更新part=101的记录时,因为A的共享锁,B也不能把他在表上的共享锁转换成意向排他锁。这就是所谓的转换死锁(Microsoft SQL Server 2000, Microsoft Press,776 )
 
IB/FB中不会发生锁转换。IB/FB只会在更新时锁住个别的行。IB/FB只会发生一种类型的死锁就是循环死锁(所有数据库都存在),也就是当用户A更新并锁住了行100,然后试图更新已经被用户B加锁并更新的行200,同时,用户B也试图更新已经被A加锁的行100。这种情况下,会发生下面两种情况之一。如果有用户在他们事务中指定了NoWait选项,那么当A试图给B已经锁住的行加锁时,会立即返回错误信息,反之亦然。如果两个用户都选择了等待加锁的行,那么锁管理器将检测到死锁并选择一个事务让其回滚。
 
 
锁冲突
 
考虑这样一种情形,当用户A对一行进行了更新操作但没有提交事务,然后A去吃午饭了。用户B执行一个包含此加锁行的SELECT操作。
 
使用MSSQLServer,用户B的事务将一直等待,直到用户A持有的锁释放为止(MSDN-Locking Architcture at )缺省设置下,没有强制超时期,也没有办法在加锁之前测试出释放的资源是否被锁,除非企图存取数据(潜在得到不确定的阻塞)”(Microsoft SQL Server 2000 Books Online, LOCK_TIMEOUT Setting)为了预防这种不确定的等待,需要设置锁的超时期,使用SET LOCK_TIMEOUT命令,但这个设置会影响连接中所有事务”(Microsoft SQL Server 2000 Books Online, SET LOCK_TIMEOUT)
  IB/FB
限制更少且更灵活。使用快照事务隔离(snapshot),你一直读的是事务开始时已经提交的行的最新版本。使用读提交(read committed)事务隔离,IB/FB给你三种选择:
  1
、读这一行最新提交的版本即使有未提交的版本存在;
  2
、等待,直到未提交的版本也提交或回滚,然后读这一行;
  3
、立即接收到一个异常警告:存在此行的一个未提交版本;
 
这些设置在事务级别,因此同一连接中,你为某一个事务的所作的设置不会限制到你为其他事务的所作的选择。

  锁升级
 
设想你正在开发一个订单录入系统。订单条目表会包含上百万条记录。你必须能够通过客户类型和销售地域中的条目为某一时期生成销售报表,报表必须基于一致的数据视图。生成年报表将在订单条目表中选择超过百万的记录。
  “
当一个事务超过升级上限时, MSSQLServer2000会自动升级行锁和页锁。比如,当一个事务需要表中的一些行时, SQLServer自动获得这些行的锁,并在包含那些行的页、表或索引上放置更高级别的意向锁。当事务持有的锁的数量超过其极限时,SQLServer会企图把表上的意向锁变为更强的锁(如意向排他锁转为排他锁).获得更强的锁后,所有此事务持有的页级和行级锁被释放,锁开销减少了。”(, Lock Escalation )锁升级的结果是整个表对其他用户不再可用。在本例中,记录上的共享锁将升级为一个表上的共享锁。于是其他所有用户都不能更新此表中的任一行。如果要更新一个表中的大量行,那么更新需要的排他锁可能升级为表级锁,以防止其他用户读和更新这张表。
  IB/FB
的版本体系结构在读记录时不需要任何锁。通过记录的不同版本,一致性的数据视图不需要放置锁,更不会阻塞其他更新操作。IB/FB的锁只是行级别的,且只在更新一行时存在,所以根本不存在锁升级的概念。
 
  

阅读(334) | 评论(0) | 转发(1) |
0

上一篇:没有了

下一篇:Part3: 触发器,恢复机制,跨平台性等

给主人留下些什么吧!~~