这是我最初的问题:
我试图弄清楚如何在 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