2010-11-12 20 views
1

我是Transact SQL編程的新手。在一次事務中SQL Server中的替代同義詞

我創建了一個存儲過程,它將刪除並創建一個現有的同義詞,以便它將指向另一個表。該存儲的過程發生在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 
... 

我們有一個應用程序會定期使用同義詞寫入數據。

我的問題是我會遇到競爭條件,同義詞被刪除,而應用程序嘗試寫入同義詞?

如果以上是一個問題,有人可以給我建議解決方案。

感謝

+1

這些被稱爲商店** D **程序 - 作爲商店** D **內SQL Server - 不「存儲*程序.... – 2010-11-12 16:52:52

回答

1

是的,你有一個競爭條件。

管理此方法的一種方法是在事務模式下BEGIN TRAN後面有sp_getapplock,並根據需要捕獲/處理返回狀態。這將逐字串行(在執行意義上,不是隔離)調用者,因此在任何時候只有一個SPID執行。

0

我相當肯定,你的確會得到競爭條件。同義詞名稱旨在用於縮短對象的名稱,而不是假設比其他對象更頻繁地更改。我通過你的描述猜測你正在使用它來重用代碼。您可能更適合使用動態SQL,而不是您已經擁有的。

有關動態SQL的更多信息,你可能想通過厄蘭Sommarskog考慮看看this article上,在他的許多答案OMG Poinies引用。特別是在與我有以下

與動態表和列 交易行情動態表和列名處理部分名稱

傳表和列名作爲參數 的程序與動態 SQL對於 應用程序代碼很少是一個好主意。 (它可以使 完全適用於管理任務)。至於 我已經說過了,你不能傳遞一個表名或 列名作爲參數到 sp_executesql,但是你必須把它插入到SQL字符串中。 作爲例行公事,您仍應該保護它免受SQL注入攻擊。 這可能是壞的來自 用戶輸入。

爲此,您應該使用 內置函數quotename()(在SQL 7中添加 )。 quotename()取兩個參數: 參數:第一個是字符串,第二個是 的一對分隔符,將字符串換行。默認爲 第二個參數是[]。因此, quotename('訂單')返回[訂單]。quotename()負責嵌套 分隔符,所以如果你有一個真正的 瘋狂的表名稱,如左]括號, quotename()將返回 [左]]括號]。

請注意,當您使用具有多個組件的名稱 ,每個 組件應單獨引用。 quotename('dbo.Orders')返回 [dbo.Orders],但這是 中的一個表,其中第一個 的四個字符是d,b,o和一個點。 只要您只使用dbo 架構,最佳做法是在 的動態SQL中添加dbo,並且只傳遞 表名稱。如果您使用不同的 模式,請將模式作爲單獨的 參數傳遞。 (雖然你可以使用 內置函數PARSENAME()分裂 起來的部分A @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.