Pet*_*son 9 t-sql sql-server table-locking
这是我最初的问题:
我试图弄清楚如何在SQL Server中强制执行EXCLUSIVE表锁.我需要解决不合作的读者(我无法控制,闭源的东西),明确地将他们的ISOLATION LEVEL设置为READ UNCOMMITTED.结果是,无论我在执行插入/更新时指定了多少锁和什么样的隔离,客户端只需要设置正确的隔离并返回读取我正在进行的垃圾.
答案结果很简单 -
虽然无法触发显式锁定,但任何DDL更改都会触发我正在寻找的锁定.
虽然这种情况并不理想(客户端阻塞而不是目击可重复读取),但它比让客户端覆盖隔离并读取脏数据要好得多.这是带有虚拟触发器锁定机制的完整示例代码
赢了!
#!/usr/bin/env perl
use Test::More;
use warnings;
use strict;
use DBI;
my ($dsn, $user, $pass) = @ENV{ map { "DBICTEST_MSSQL_ODBC_$_" } qw/DSN USER PASS/ };
my @coninf = ($dsn, $user, $pass, {
AutoCommit => 1,
LongReadLen => 1048576,
PrintError => 0,
RaiseError => 1,
});
if (! fork) {
my $reader = DBI->connect(@coninf);
$reader->do('SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED');
warn "READER $$: waiting for table creation";
sleep 1;
for (1..5) {
is_deeply (
$reader->selectall_arrayref ('SELECT COUNT(*) FROM artist'),
[ [ 0 ] ],
"READER $$: does not see anything in db, sleeping for a sec " . time,
);
sleep 1;
}
exit;
}
my $writer = DBI->connect(@coninf);
eval { $writer->do('DROP TABLE artist') };
$writer->do('CREATE TABLE artist ( name VARCHAR(20) NOT NULL PRIMARY KEY )');
$writer->do(do('DISABLE TRIGGER _lock_artist ON artist');
sleep 1;
is_deeply (
$writer->selectall_arrayref ('SELECT COUNT(*) FROM artist'),
[ [ 0 ] ],
'No rows to start with',
);
$writer->begin_work;
$writer->prepare("INSERT INTO artist VALUES ('bupkus') ")->execute;
# this is how we lock
$writer->do('ENABLE TRIGGER _lock_artist ON artist');
$writer->do('DISABLE TRIGGER _lock_artist ON artist');
is_deeply (
$writer->selectall_arrayref ('SELECT COUNT(*) FROM artist'),
[ [ 1 ] ],
'Writer sees inserted row',
);
# delay reader
sleep 2;
$writer->rollback;
# should not affect reader
sleep 2;
is_deeply (
$writer->selectall_arrayref ('SELECT COUNT(*) FROM artist'),
[ [ 0 ] ],
'Nothing committed (writer)',
);
wait;
done_testing;
READER 27311: waiting for table creation at mssql_isolation.t line 27. ok 1 - READER 27311: does not see anything in db, sleeping for a sec 1310555569 ok 1 - No rows to start with ok 2 - Writer sees inserted row ok 2 - READER 27311: does not see anything in db, sleeping for a sec 1310555571 ok 3 - READER 27311: does not see anything in db, sleeping for a sec 1310555572 ok 3 - Nothing committed (writer) ok 4 - READER 27311: does not see anything in db, sleeping for a sec 1310555573 ok 5 - READER 27311: does not see anything in db, sleeping for a sec 1310555574
小智 6
一个hack hack hack方法是强制对表进行操作,该操作对表进行SCH-M锁定,即使在READ UNCOMMITTED隔离级别也会阻止对表的读取.例如,作为操作的一部分,执行类似ALTER TABLE REBUILD的操作(可能在特定的空分区上以减少性能影响)将阻止对表的所有并发访问,直到您提交为止.
添加锁定提示到您的SELECT:
SELECT COUNT(*) FROM artist WITH (TABLOCKX)
并把你INSERT进入交易.
如果您的初始语句是在显式事务中,则SELECT它将在处理之前等待锁定.