T-SQL事务如何不是线程安全的?

时间:2009-02-12 19:56:02

标签: sql-server multithreading tsql transactions transaction-isolation

以下(已清理的)代码有时会产生以下错误:

  

无法删除表'database.dbo.Table',因为它不存在或您没有权限。
  数据库中已经有一个名为“Table”的对象。

begin transaction  
    if exists (select 1 from database.Sys.Tables where name ='Table') 
        begin drop table database.dbo.Table end 

    Select top 3000 *
    into database.dbo.Table
    from OtherTable
commit

select * from database.dbo.Table

代码可以同时运行多次。有人知道它为什么会破裂吗?

3 个答案:

答案 0 :(得分:7)

我可以问你为什么先这样做吗?您应该考虑使用临时表或提出另一种解决方案。

我不肯定DDL语句在事务中的行为与DML语句相同,并且看到一篇博客文章有一个奇怪的行为并在DDL中创建存储过程。

请注意,您可能需要验证事务隔离级别并将其设置为Serialized。

修改

基于快速测试,我在两个不同的连接中运行相同的sql,当我创建表但没有提交事务时,第二个事务被阻止。所以它看起来应该有效。我仍然会警告这种类型的设计。

答案 1 :(得分:3)

您在代码的哪个部分阻止了对此资源的多次访问?

begin transaction  
    if exists (select 1 from database.Sys.Tables where name ='Table') 
        begin drop table database.dbo.Table end 

    Select top 3000 *
    into database.dbo.Table
    from OtherTable
commit

开始交易没有这样做。它仅为添加到表的任何行设置提交/回滚方案。

(如果存在,丢弃)是竞争条件,同时使用(select..into)重新创建表。 Mutiliple人一下子进入该代码将肯定会导致各种错误。有些人正在创建其他人刚刚销毁的表,有些人正在删除不再存在的表,而其他人正在删除一些正忙着插入的表。 UGH!

考虑其他人的临时表建议,或者如果关键资源繁忙,则使用应用程序锁来阻止其他人输入此代码。 drop / create上的事务不是你想要的。

答案 2 :(得分:1)

如果您只是在此过程中使用此表,我建议使用临时表,或者根据数据量,使用ram表。我经常使用ram表来避免任何交易成本并节省磁盘活动。