Вставка уникальной строки SQL Server из хранимой процедуры не работает - PullRequest
0 голосов
/ 03 февраля 2012

У меня есть страница в нашей интрасети, которая отправляет запросы в CGI-скрипт Perl.Этот скрипт, в свою очередь, вызывает хранимую процедуру в БД SQL Server, которая проверяет, существует ли объект с определенными атрибутами.Если это так, storproc возвращает идентификатор инструмента, если нет, он создает новый инструмент и возвращает идентификатор этого нового инструмента.Хранимая процедура создает транзакцию, а также использует with (TABLOCKX) в операторе вставки.Для удобства, когда указанный пользователь одновременно отправляет несколько запросов, веб-страницы отправляют запросы в сценарий perl асинхронно.Я подумал, что когда будет отправлено несколько запросов, требующих нового инструмента, первый, ударивший storproc, запустится, заблокирует таблицу, создаст новый инструмент, снимет блокировку, а затем последующие вызовы storproc будут известныновый инструмент и использовать его.На практике я увидел, что будет несколько запросов на создание нового инструмента, а остальные будут использовать самый последний.Я пытался использовать setTimeout на стороне клиента для распределения запросов, но, похоже, это не имеет значения.Любые идеи относительно того, что я могу делать неправильно?

Вот код хранимой процедуры:

CREATE PROCEDURE [dbo].[CreateFutures]
@code varchar(5),
@month int,
@year int,
@currency varchar(3)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION

declare @ticker varchar(7)
declare @yearCode char(1)
declare @res as Table (id int)
declare @n as int

set @yearCode = convert(char(1), @year % 10)

set @ticker = (
    select @code + futures + @yearCode
    from FuturesMonthCodes 
    where month = @month
)

insert into @res
select top 1 instrument
from InstrumentFutures // This is a view that joins InstrumentText and InstrumentNumber data
where ticker = @ticker
and code = @code
and month = @month
and year = @year
and currency = @currency
order by instrument

set @n = (select COUNT(id) from @res)

if @n = 0
    begin
        print 'Creating Future'
        declare @id int
        declare @stamp datetime
        set @stamp = CURRENT_TIMESTAMP
        insert into Instrument with (TABLOCKX) (insertTime) values (@stamp)
        set @id = (select SCOPE_IDENTITY());

        insert into InstrumentText      (instrumentId, name, value) values (@id, 'type',    'futures')
        insert into InstrumentText      (instrumentId, name, value) values (@id, 'ticker',  @ticker)
        insert into InstrumentText      (instrumentId, name, value) values (@id, 'code',    @code)
        insert into InstrumentText      (instrumentId, name, value) values (@id, 'currency',@currency)
        insert into InstrumentNumber    (instrumentId, name, value) values (@id, 'month',   @month)
        insert into InstrumentNumber    (instrumentId, name, value) values (@id, 'year',    @year)

        insert into @res (id) values (@id)
    end
commit transaction

if @n = 0 --instrument created
    select top 1 id, 1 from @res order by id
else --returning existing instrument
    select top 1 id, 0 from @res order by id
END

1 Ответ

1 голос
/ 03 февраля 2012

Это проблема sql больше, чем perl.

Допустим, 3 сценария пытаются запустить этот сохраненный процесс в одно и то же время.

Первый запуск, и таблица заблокирована.Другие ждали, пока таблица разблокируется, но они не перечитывают данные, когда блокировка завершена, поэтому они использовали старые данные.

Если ваш сохраненный процесс делает выбор, вы должны повторно запустить его после снятия блокировки.

С уважением,

...