为什么 T-SQL 事务不是线程安全的?

发布于 2024-07-14 02:46:22 字数 455 浏览 11 评论 0原文

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

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

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

The following (sanitized) code sometimes produces these errors:

Cannot drop the table 'database.dbo.Table', because it does not exist or you do not have permission.
There is already an object named 'Table' in the database.

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

The code can be run multiple times simultaneously. Anyone know why it breaks?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

野却迷人 2024-07-21 02:46:23

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

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

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

编辑

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

Can I ask why your doing this first? You should really consider using temporary tables or come up with another solution.

I'm not positive that DDL statments behave the sameway in transactions as DML statements and have seen a blog post with a weird behavior and creating stored procedures within a DDL.

Asside from that you might want to verify your transaction isolation level and set it to Serialized.

Edit

Based on a quick test, I ran the same sql in two different connections, and when I created the table but didn't commit the transaction, the second transaction blocked. So it looks like this should work. I would still caution against this type of design.

偷得浮生 2024-07-21 02:46:23

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

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) 重新创建表。 多人同时投入该代码肯定会导致各种错误。 有些创建了其他表刚刚销毁的表,有些删除了不再存在的表,还有一些删除了一些正在忙于插入的表。 啊!

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

In what part of the code are you preventing multiple accesses to this resource?

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

Begin transaction isn't doing it. It's only setting up for a commit/rollback scenario on any rows added to tables.

The (if exists, drop) is a race condition, along with the re-creation of the table with (select..into). Mutiliple people dropping into that code all at once will most certainly cause all kinds of errors. Some creating tables that others have just destroyed, others dropping tables that don't exist anymore, and others dropping tables that some are busy inserting into. UGH!

Consider the temp table suggestions of others, or using an application lock to block others from entering this code at all if the critical resource is busy. Transactions on drop/create are not what you want.

听风念你 2024-07-21 02:46:23

如果您在此过程中仅使用此表,我建议使用临时表或 RAM 表(具体取决于数据量)。 我经常使用内存表来避免任何事务成本并节省磁盘活动。

If you are just using this table during this process I would suggest using a temp table or , depending on how much data , a ram table. I use ram tables frequently to avoid any transaction costs and save on disk activity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文