这是我最初的问题:
我试图弄清楚如何在 SQL Server 中强制执行 EXCLUSIVE 表锁。我需要解决不合作的读者(超出我的控制,封闭源代码的东西),它们明确地将他们的隔离级别设置为未提交的阅读。效果是,无论我在执行插入/更新时指定了多少锁和哪种隔离,客户端只需要设置正确的隔离并返回读取我正在进行的垃圾。
答案原来很简单——
虽然无法触发显式锁,但任何 DDL 更改都会触发我正在寻找的锁。
虽然这种情况并不理想(客户端阻塞而不是见证可重复读取),但它比让客户端覆盖隔离并读取脏数据要好得多。这是带有虚拟触发锁定机制的完整示例代码
赢了!
#!/usr/bin/env perl 使用测试::更多; 使用警告; 使用严格; 使用 DBI; 我的 ($dsn, $user, $pass) = @ENV{ map { "DBICTEST_MSSQL_ODBC_$_" } qw/DSN USER PASS/ }; 我的@coninf = ($dsn, $user, $pass, { 自动提交 => 1, LongReadLen => 1048576, 打印错误 => 0, 提升错误 => 1, }); 如果(!叉子){ 我的 $reader = DBI->connect(@coninf); $reader->do('SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'); warn "READER $$: 等待创建表"; 睡觉1; 对于 (1..5) { is_deeply ( $reader->selectall_arrayref ('SELECT COUNT(*) FROM Artist'), [ [ 0 ] ], “阅读器 $$:在 db 中看不到任何内容,正在休眠一秒钟”。时间, ); 睡觉1; } 出口; } 我的 $writer = DBI->connect(@coninf); eval { $writer->do('DROP TABLE Artist') }; $writer->do('CREATE TABLE 艺术家 (name VARCHAR(20) NOT NULL PRIMARY KEY)'); $writer->do(do('DISABLE TRIGGER _lock_artist ON 艺术家'); 睡觉1; is_deeply ( $writer->selectall_arrayref ('SELECT COUNT(*) FROM Artist'), [ [ 0 ] ], '没有行开头', ); $writer->开始工作; $writer->prepare("INSERT INTO Artist VALUES ('bupkus')")->execute; # 这就是我们锁定的方式 $writer->do('ENABLE TRIGGER _lock_artist ON 艺术家'); $writer->do('禁用触发 _lock_artist ON 艺术家'); is_deeply ( $writer->selectall_arrayref ('SELECT COUNT(*) FROM Artist'), [ [ 1 ] ], '作家看到插入的行', ); # 延迟阅读器 睡觉 2; $writer->回滚; # 不应影响阅读器 睡觉 2; is_deeply ( $writer->selectall_arrayref ('SELECT COUNT(*) FROM Artist'), [ [ 0 ] ], '没有承诺(作家)', ); 等待; 完成测试;
结果:
阅读器 27311:等待在 mssql_isolation.t 第 27 行创建表。 好的 1 - 阅读器 27311:在 db 中看不到任何东西,睡了一秒钟 1310555569 ok 1 - 没有行开始 ok 2 - Writer 看到插入的行 好的 2 - 阅读器 27311:在 db 中看不到任何东西,睡了一秒钟 1310555571 好的 3 - 阅读器 27311:在 db 中看不到任何东西,睡了一秒钟 1310555572 好的 3 - 没有承诺(作家) 好的 4 - 阅读器 27311:在 db 中看不到任何东西,睡了一秒钟 1310555573 好的 5 - 阅读器 27311:在 db 中看不到任何东西,睡了一秒钟 1310555574