Это был мой исходный вопрос:
Я пытаюсь выяснить, как принудительно установить ИСКЛЮЧИТЕЛЬНЫЕ блокировки таблиц в SQL Server. Мне нужно работать с неконтролируемыми читателями (вне моего контроля, материалы с закрытым исходным кодом), которые явно устанавливают свой УРОВЕНЬ ИЗОЛЯЦИИ на ЧИТАТЬ НЕПРЕРЫВНО. Эффект состоит в том, что независимо от того, сколько блокировок и какой тип изоляции я указываю при выполнении вставки / обновления, клиенту просто нужно установить правильную изоляцию и он возвращается к чтению моего незавершенного мусора.
Ответ повернулся. выглядит довольно просто -
хотя нет возможности активировать явную блокировку, любое изменение DDL запускает блокировку, которую я искал.
Хотя эта ситуация не идеальна (клиент блокируется вместо того, чтобы наблюдать повторяющиеся чтения), это намного лучше, чем позволить клиенту переопределить изоляцию и прочитать грязные данные. Вот полный пример кода с механизмом фиксации триггера
WINNING!
#!/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