Рассмотрите базу данных SQL Server и две сохраненные процедуры:SQL Server: предотвращение грязных чтений в хранимой процедуре
* 1. Прок, который выполняет 3 важные вещи в транзакции: создайте клиента, вызовите sproc для выполнения другой вставки и условно вставьте третью запись с новым идентификатором.
BEGIN TRAN
INSERT INTO Customer(CustName) (@CustomerName)
SELECT @NewID = SCOPE_IDENTITY()
EXEC CreateNewCustomerAccount @NewID, @CustomerPhoneNumber
IF @InvoiceTotal > 100000
INSERT INTO PreferredCust(InvoiceTotal, CustID) VALUES (@InvoiceTotal, @NewID)
COMMIT TRAN
* 2. Сохраненная процедура, которая опросает таблицу Customer
для новых записей, которые не имеет, имеет соответствующую запись PreferredCust
. Клиентское приложение выполняет опрос, вызывая этот хранимый процесс каждые 500 мс. SELECT на Customer
НЕ включает транзакцию.
--not in the Preferred list
SELECT C.ID
FROM Customer AS C
LEFT JOIN PreferredCust AS PRE ON PRE.CustID = C.ID
WHERE PRE.CustID IS NULL
Проблема возникла, когда процедура опроса хранится нашел запись в таблице Customer
, и вернула его как часть его результатов. Проблема заключалась в том, что он взял эту запись, я предполагаю, как часть грязного чтения. Запись закончилась тем, что позже появилась запись в PreferredCust
, и в итоге возникла проблема с нисходящим потоком.
Вопрос
- Как вы можете явно предотвратить грязное чтение этой второй хранимая процедура?
- Насколько вероятно мое предположение о сценарии грязного чтения?
Среда SQL Server 2005 с конфигурацией по умолчанию из коробки. Никакие другие блокирующие удары не указаны в любой из этих хранимых процедур.
Эти два хранимых procs вызываются с Java-клиента через соединение JDBC. Неизвестно, используют ли они одно и то же соединение, но SQL Profiler показывает, что они используют тот же SPID и ClientProcessID.
Вот что показывает SQL Profiler:
SELECT @@MAX_PRECISION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SET IMPLICIT_TRANSACTIONS OFF
SET QUOTED_IDENTIFIER ON
SET TEXTSIZE 2147483647
go
EXEC WriteNewCustomer 'CustomerX', 199000
go
--get any customers in the priority
SELECT @@MAX_PRECISION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SET IMPLICIT_TRANSACTIONS OFF
SET QUOTED_IDENTIFIER ON
SET TEXTSIZE 2147483647
go
EXEC GetCustomersWithLowInvoice
go
Не требуется ли вторая процедура в рамках транзакции? –
@ Майкл: спасибо за идею. Никакой транзакции по этому поводу не читается. Интересно, будет ли добавление того, что чтение в транзакции будет иметь какой-либо эффект. –