单个TRANSACTION中循环的行为

时间:2012-11-09 17:10:39

标签: sql sql-server sql-server-2008-r2

我有以下结构:

PROCEDURE A

BEGIN TRANSACTION
    WHILE <loops 20 times>
        BEGIN

         --10 minute script     
         --INSERT a single record into table X

        END
COMMIT TRANSACTION


PROCEDURE B - This is run via the agent every 10 minutes it scans table X for any new entries and if it finds any it sends an e-mail

如果一切正常,20个新记录将添加到表X中 - 如果所有20个循环都成功,这些记录是否只会添加到X?如果循环到达它的第5次迭代,然后错误将提交前4条记录?

2 个答案:

答案 0 :(得分:4)

好吧,持有10分​​钟的交易是邪恶的。交易开放20次,持续10分钟......好吧,是恶意的20倍。长期事务非常非常具有破坏性,它们会导致锁定和阻塞,日志使用和增长,恢复问题等严重问题。切勿设计交易时间超过的任何内容。是时候重新审视你想要解决的根本问题,并提出一个截然不同的解决方案。

至于核心问题:事务可以在这样的迭代中使用保存点,因此即使迭代5遇到问题并且必须回滚,也会保存(提交)迭代1-4。诀窍是回滚到保存点,而不是完全回滚。遵循与Exception Handling and Nested Transactions中相同的模式。请注意,不是每个错误都是可恢复的,一些错误会强制完全回滚(例如,死锁是典型的例子)。

答案 1 :(得分:1)

这里答案不是百分之百直接:

它们将被添加到内存中的数据页面,因为它们在每个循环结束时插入,如果另一个进程使用READ UnCOMITTED或NO LOCK运行,那么它们将能够看到这些插入。这称为Dirty Reads,REAd COMMITED的默认隔离级别可以防止这种情况,但这也意味着将阻止事务在此级别下读取它,直到循环完成。

但是,SQL Server可以随时选择将脏页刷新到光盘。通过这种方式,我的意思是在交易结束之前,交易结束时或交易完成之后。

可以肯定的是,在提交之前,写入将在事务结束时刷新到事务日志。这就是SQL Server gauruntees数据在数据库发生故障时不会丢失的方式。这称为WAL或Write Ahead Logging。