Как явно заблокировать таблицу в Microsoft SQL Server (ищу взлом - не взаимодействующий клиент)

Это был мой исходный вопрос:

Я пытаюсь выяснить, как принудительно установить ИСКЛЮЧИТЕЛЬНЫЕ блокировки таблиц в 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
9
задан emlai 15 July 2015 в 01:10
поделиться