Альтернативный синоним в SQL Server в одной транзакции - PullRequest
1 голос
/ 12 ноября 2010

Я новичок в программировании на Transact SQL.

Я создал хранимую процедуру, которая удаляла бы и создавал существующий синоним, чтобы он указывал на другую таблицу.Хранимая процедура принимает 2 параметра:

  • synonymName - существующий синоним
  • nextTable - таблица, на которую нужно указать

Это фрагмент кода:

...
BEGIN TRAN SwitchTran
   SET @SqlCommand='drop synonym ' + @synonymName
   EXEC sp_executesql @SqlCommand
   SET @SqlCommand='create synonym ' + @synonymName + ' for ' + @nextTable
   EXEC sp_executesql @SqlCommand
COMMIT SwitchTran
...

У нас есть приложение, которое регулярно записывает данные с использованием синонима.

У меня вопрос, не возникну ли я в состоянии гонки, когда синоним отбрасывается, а приложение пытаетсянаписать в синоним?

Если вышеупомянутое является проблемой, кто-то может дать мне предложение по решению.

Спасибо

Ответы [ 2 ]

1 голос
/ 12 ноября 2010

Да, у вас будет состояние гонки.

Один из способов справиться с этим - иметь sp_getapplock после BEGIN TRAN в режиме транзакции и перехватывать / обрабатывать статус возврата по мере необходимости.Это будет буквально сериализовать (в смысле выполнения, а не изоляции) вызывающих, так что только один SPID выполняется одновременно.

0 голосов
/ 12 ноября 2010

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

Для получения дополнительной информации о динамическом SQL, возможно, вы захотите взглянуть на эту статью , написанную Эрландом Соммарскогом, в которой OMG Poinies ссылается во многих его ответах. В частности, раздел «Работа с динамическими таблицами и именами столбцов», который я цитирую ниже

Работа с динамической таблицей и столбцом Имена

Передача имен таблиц и столбцов как параметры процедуры с динамическим SQL редко является хорошей идеей для код приложения. (Это может сделать отлично подходит для задач администратора). Как Я сказал, что вы не можете передать стол или имя столбца в качестве параметра для sp_executesql, но вы должны интерполировать его в строку SQL. Тем не менее, вы должны защитить его от SQL-инъекция, как обычно. Это может быть так плохо, это исходит от пользовательский ввод.

Для этого вы должны использовать встроенная функция quotename () (добавлено в SQL 7). quotename () занимает два параметры: первая строка, и вторая пара разделителей обернуть строку. По умолчанию для второй параметр - []. Таким образом, quotename ('Orders') возвращает [Orders]. quotename () заботится о вложенных разделители, так что если у вас есть действительно сумасшедшее имя таблицы, как Left] Bracket, quotename () вернется [Влево]] Кронштейн].

Обратите внимание, что при работе с именами с несколькими компонентами, каждый Компонент должен быть указан отдельно. Возвращает quotename ('dbo.Orders') [dbo.Orders], но это таблица в неизвестная схема которой первая четыре символа - это d, b, o и точка. Пока вы работаете только с ДБО схема, лучшая практика заключается в добавлении DBO в динамический SQL и только передать имя таблицы Если вы работаете с разными схемы, передайте схему как отдельную параметр. (Хотя вы могли бы использовать встроенная функция parsename () для разделения до параметра @tblname по частям.)

Хотя general_select все еще плохой идея как хранимая процедура, здесь тем не менее версия, которая обобщает некоторые хорошие достоинства кодирования для динамического SQL:

CREATE PROCEDURE general_select @tblname nvarchar(128),
                                @key     varchar(10),
                                @debug   bit = 0 AS DECLARE @sql nvarchar(4000) 
            SET @sql = 'SELECT col1, col2, col3
            FROM dbo.' + quotename(@tblname) + '
            WHERE keycol = @key' IF @debug = 1
            PRINT @sql EXEC sp_executesql @sql, N'@key varchar(10)', @key = @key 

            - I'm using sp_executesql rather than EXEC().
            - I'm prefixing the table name with dbo. 
            - I'm wrapping @tblname in quotename(). 
            - There is a @debug parameter.
...