【问题标题】:Database Isolation Models数据库隔离模型
【发布时间】:2012-11-16 06:20:47
【问题描述】:

我有一个带有“ID”列的数据库。每当数据库有新条目时,我都会从数据库中获取最后一个 ID,增加值,然后在 Insert 语句中使用它。

编辑:我需要在多个插入语句中使用 ID。我将从主表中获取此 ID,并使用此 ID 将值插入相关表中。

    NextID = Select Max(ID) + 1 From Table

    INSERT INTO Table1(ID, Col1, Col2...) Values(NextId, Value1, Value2...)

    INSERT INTO Table2 (ID,col1,col2....) Values (NextID, Value1, Value2...)

我不知道这是否是一个好方法,因为我知道会有并发问题。 当我的应用程序尝试读取 NextID 时,有可能该应用程序的另一个实例也尝试读取相同的值,因此可能会出现并发问题。

是否有适当的方法来处理这种情况?我的意思是有一些方法可以设置数据库隔离级别。对于这种情况,这将是一个合适的隔离级别。

另外,如果有人可以建议我使用另一种方法来手动维护和增加数据库中的 ID,我也愿意接受。

如果这些信息还不够,请告诉我您需要什么。

我正在使用带有 VB 和 MS Sql Server 2008 的 ASP.Net。我不想使用 SQL Server 的内置“身份”。

【问题讨论】:

  • 在一个语句中完成......
  • @MitchWheat 单条语句是什么意思?我也有同样的问题...请建议。
  • @MitchWheat 是的,这是一个选项,但我需要在多个插入语句中使用该 ID。我将从主表中读取 nextID 并使用该 ID 插入到其他相关表中。
  • 我知道您不想使用identity,但这确实是您问题的解决方案。如果您可以解释您在身份方面遇到的问题,也许有人可以就如何解决这个问题提出建议。
  • @MikaelEriksson 是的,实际上身份的问题是我的问题中的 ID 是可编辑的(不是由用户,其他一些逻辑),如果我使用身份,则无法完成。我知道,允许修改 ID 是不明智的,但我需要这个逻辑。

标签: asp.net sql-server vb.net sql-server-2008 sql-server-2008-r2


【解决方案1】:

获取下一个 ID 的唯一方法是实际插入行,并使用标识。其他一切都会失败。因此,您必须首先插入父表:

begin transaction;
insert into Table (col1, col2, col3) values (value1, value2, value3);
set @Id = scope_identity();
insert into Table1(ID, col1, col2) values (@Id, ...);
insert into Table3(ID, col1, col2) values (@Id, ...);
commit;

这是原子和并发安全的。

我不想使用 SQL Server 的内置“身份”。

tl;博士。除非您能明确说明为什么,否则您“想要”的东西并不重要。你可以正确地做到这一点,或者你可以花时间重新发明轮子。

【讨论】:

  • 是的,实际上Identity的问题是我的问题中的ID是可编辑的(不是由用户,其他一些逻辑),如果我使用Identity则无法完成。我知道,允许修改 ID 是不明智的,但我需要这个逻辑。
  • 使用不可变的身份作为主键。使用不同的属性作为“逻辑 ID”。编辑你的可变逻辑 ID 令人作呕,但不要触摸主键不可变身份。
  • 很抱歉,我有点困惑,我应该使用“身份”还是“逻辑 ID”作为我的 ID 列。请多多包涵
  • ID 将是身份。永远不要向用户显示 ID,永远不要在更改“逻辑 ID”的逻辑中使用它。 “逻辑 ID”(默认情况下可以在记录插入时获取 ID 值)是“必须更改 ID”时显示和操作的 ID。
  • 换句话说,使用surrogate key作为主键物理ID。
【解决方案2】:

基本上,您有一组三个 SQL 语句 - 一个选择和两个插入。数据库引擎可以在它们之间的任何位置从不同的会话执行另一条语句,从而破坏您的数据一致性——其他一些会话可以获得与您获得的相同的 MAX() 值并将其用于其他插入语句。阻止数据库引擎这样做的唯一方法是使用事务。用 BEGIN TRANSACTION ... COMMIT 包装你的批次,你就完成了。

【讨论】:

    【解决方案3】:

    你做这件事的方式很好,你需要的是事务处理..

    BEGIN TRANSACTION 
    
    begin try
        NextID = Select Max(ID) + 1 From Table
    
        INSERT INTO Table1(ID, Col1, Col2...) Values(NextId, Value1, Value2...)
    
        INSERT INTO Table2 (ID,col1,col2....) Values (NextID, Value1, Value2...)
    
        COMMIT TRANSACTION 
    end try
    
    begin catch
    
        ROLLBACK TRANSACTION 
        --exception logging goes here
    
    end catch
    

    【讨论】:

    • 并发访问会怎样?我的意思是假设我正在通过交易获取 nextID。现在它会锁定 ID 列吗?如果之前的 Committed ID 是 5,第一个请求会得到 5+1=6,但是在这个事务被提交之前,假设在下一毫秒另一个请求来读取 Max(ID) 的值,它将返回哪个值.. 最后提交的 5 + 1=6 或 6+1=7 ?我希望我没有让你感到困惑:P
    • 这会有任何相关的性能问题吗?我的意思是如果有很多请求,隔离是否会减慢系统速度?
    • 不应该,除非您的实际插入速度很快,即 table1 和 table2 没有很多索引,这会使插入速度变慢。并且父“表”中的 ID 列被索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-23
    • 2012-08-02
    • 2016-09-20
    相关资源
    最近更新 更多