以下(已清理的)代码有时会产生以下错误:
无法删除表'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
代码可以同时运行多次。有人知道它为什么会破裂吗?
答案 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表来避免任何交易成本并节省磁盘活动。