2

以下(经过清理的)代码有时会产生这些错误:

无法删除表“database.dbo.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

代码可以同时运行多次。有谁知道为什么会断?

4

3 回答 3

7

我能问一下你为什么先这样做吗?您真的应该考虑使用临时表或提出其他解决方案。

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

除此之外,您可能希望验证您的事务隔离级别并将其设置为序列化。

编辑

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

于 2009-02-12T20:03:56.963 回答
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

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

(if exists, drop) 是一个竞争条件,以及使用 (select..into) 重新创建表。多人同时进入该代码肯定会导致各种错误。一些创建其他人刚刚销毁的表,另一些删除不再存在的表,还有一些删除一些正忙于插入的表。啊!

考虑其他人的临时表建议,或者在关键资源繁忙时使用应用程序锁来阻止其他人输入此代码。删除/创建事务不是您想要的。

于 2009-02-12T21:45:44.393 回答
1

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

于 2009-02-12T20:17:19.067 回答