我应该使用哪种隔离级别来预订航班

时间:2012-03-16 12:09:40

标签: isolation-level

我有一个航班预订程序使用mssql ,对于预订航班,我想确定我应该使用隔离级别还是锁?

(这是一个示例代码,我的问题是这种情况的隔离级别不做预订)

我的数据库有一个库存表,如:

Inventory Table
------------------------
id (Pk),
FlightNumber,
Total,
Sold

现在如果有人想预订航班,我会在交易中使用此代码

Decalre @total int;
Decalre @sold int;
Select @total=Total,@sold=Sold From Inventory where FlightNumber='F3241b';

IF @total-@sold > 0
BEGIN
   Update inventory set Sold=Sold+1 where FlightNumber='F3241b';
   PRINT 'Reserve Complete'
END
ELSE
PRINT 'this flight is full' 

我有这些问题:

Q1:我应该使用锁定还是隔离级别?使用锁定或隔离级别是否有任何好处?

Q2:根据Q1我应该使用哪种隔离级别或锁定

3 个答案:

答案 0 :(得分:4)

如果您正在寻找哪种隔离级别可以使示例代码按原样运行,而不是解决示例代码所解决问题的最佳方法,那么您至少需要保证REPEATABLE READ

使用严格的两阶段锁定(S2PL)进行并发的数据库允许READ COMMITTED事务在每个语句完成时丢弃共享锁,甚至更早,因此在事务A检查可用性和声明席位的时间之间,其他人可以使用事务B并再次读取,而不会导致任何事务失败。交易A可能会暂时阻止交易B,但两者都会更新,您可能会被过度销售。

在使用多版本并发控制(MVCC)进行并发的数据库中,读取不阻止写入和写入不会阻止读取。在READ COMMITTED,每个语句根据已提交的内容使用数据库的新快照,并且至少在某些情况下(我知道在PostgreSQL中也是如此),并发写入的解决没有错误。因此,即使事务A正在更新已售出的计数,或者已经这样做而未提交,事务B也会看到旧计数并继续更新。当它尝试更新时,它可以阻止等待先前的更新,但是一旦提交,它将找到该行的新版本,检查它是否符合选择标准,如果是,则更新,如果没有则忽略该行,并且继续提交没有错误。所以,再次,你是过度销售。

如果您选择使用事务隔离,我猜这会回答Q2。通过修改示例代码以获取显式锁定,可以在较低的隔离级别解决该问题,但这通常会导致使用隔离级别更严重的阻塞,该隔离级别足以自动处理它。

答案 1 :(得分:2)

你的事情过于复杂。您的所有查询都可以替换为:

Update inventory
set Sold = Sold + 1
where FlightNumber = 'F3241b'
AND Total - Sold > 0  -- Important!

如果航班已满,则不会发生更新(不符合第二个条件),它将返回0个已修改的行。如果是这种情况则表示航班已满。否则,查询会修改Sold值并返回1已修改的行。

在这种情况下,任何隔离级别都可以,因为单个查询始终是原子的。这有点类似于

BTW此查询可以轻松调整,以允许以原子方式进行任意数量的预订:

Update inventory
set Sold = Sold + @seats
where FlightNumber = 'F3241b'
AND Total - Sold >= @seats

答案 2 :(得分:0)

请参阅此链接以解释SQL Server中的SNAPSHOT ISOLATION级别。 http://msdn.microsoft.com/en-us/library/ms345124(v=sql.90).aspx

他们谈论汽车租赁应用程序。

如果您需要更严格的隔离级别,可以移至IsolationLevel Serializable。但请注意,这很容易锁定并可能影响您的表现。