这是我的原始问题:
我正在尝试强制执行SQL Server中的独占表锁。我需要解决不配合的读者(超出我的控制范围,闭源东西),他们明确将隔离级别设置为READ UNCOMMITTED。效果是,无论我在插入/更新时指定多少锁定和什么类型的隔离,客户端只需要设置正确的隔离级别就可以重新阅读我的垃圾进度。
答案其实很简单 -
虽然没有办法触发显式锁定,但任何DDL更改都会触发我正在寻找的锁定。
虽然这种情况并不理想(客户端被阻止而不是见证可重复读取),但它比让客户端覆盖隔离并读取脏数据要好得多。这里是带有虚拟触发器锁定机制的完整示例代码
胜利!
我正在尝试强制执行SQL Server中的独占表锁。我需要解决不配合的读者(超出我的控制范围,闭源东西),他们明确将隔离级别设置为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 ] ], '没有行开始', ); $writer->begin_work; $writer->prepare("INSERT INTO artist VALUES ('bupkus') ")->execute; # 这是我们锁定的方式 $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看到插入的行', );
# 延迟读者 sleep 2; $writer->rollback;
# 不应影响读者 sleep 2;
is_deeply ( $writer->selectall_arrayref ('SELECT COUNT(*) FROM artist'), [ [ 0 ] ], '没有提交的内容(writer)', );
wait;
done_testing;
WITH (READCOMMITTED)
作为提示即可。 - zinglon