2010-11-12 55 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.