更新带有时间戳列的链接服务器表时乐观并发检查失败

Ric*_*ich 5 sql-server

I\xe2\x80\x99m 尝试使用如下代码更新链接服务器上数据库中的表:

\n\n
declare @FirstName nvarchar(30);\ndeclare @LastName nvarchar(50);\ndeclare @AccountNumber nvarchar(30);\n\nset @FirstName = N\'John\';\nset @LastName = N\'Smith\';\nset @AccountNumber = N\'ABC001\';\n\nupdate RemoteServer.MyDB.dbo.Customer\nset    FirstName = @FirstName,\n       LastName = @LastName\nwhere  AccountNumber = @AccountNumber;\n
Run Code Online (Sandbox Code Playgroud)\n\n

远程服务器也是一个 SQL Server 实例,其定义如下:

\n\n
EXEC master.dbo.sp_addlinkedserver @server = N\'RemoteServer\'\n        , @srvproduct=N\'SQL Server\'\n /* For security reasons the linked server remote logins password is\n         changed with ######## */\nEXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N\'RemoteServer\'\n        ,@useself=N\'False\'\n        ,@locallogin=NULL\n        ,@rmtuser=N\'sa\'\n        ,@rmtpassword=\'########\'\n\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'collation compatible\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'data access\', @optvalue=N\'true\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'dist\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'pub\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'rpc\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'rpc out\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'sub\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'connect timeout\', @optvalue=N\'0\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'collation name\', @optvalue=null\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'lazy schema validation\', @optvalue=N\'false\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'query timeout\', @optvalue=N\'0\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'use remote collation\', @optvalue=N\'true\'\nGO\n\nEXEC master.dbo.sp_serveroption @server=N\'RemoteServer\'\n        , @optname=N\'remote proc transaction promotion\', @optvalue=N\'true\'\nGO\n
Run Code Online (Sandbox Code Playgroud)\n\n

客户表定义为

\n\n
CREATE TABLE [dbo].[Customer](\n    [ID] [int] IDENTITY(1,1) NOT NULL,\n    [AccountNumber] [nvarchar](20) NOT NULL,\n    [FirstName] [nvarchar](30) NOT NULL,\n    [LastName] [nvarchar](50) NOT NULL,\n    [DBTimeStamp] [timestamp] NULL,\n CONSTRAINT [PK_Customer] PRIMARY KEY NONCLUSTERED \n(\n    [ID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF\n        , IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON\n        , ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\n
Run Code Online (Sandbox Code Playgroud)\n\n

并在时间戳列上有一个索引

\n\n
CREATE UNIQUE CLUSTERED INDEX [IX_Customer_TimeStamp] ON [dbo].[Customer]\n(\n    [DBTimeStamp] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF\n        , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF\n        , ONLINE = OFF, ALLOW_ROW_LOCKS = ON\n        , ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n
Run Code Online (Sandbox Code Playgroud)\n\n

当我运行查询时,我收到此错误消息:

\n\n
The OLE DB provider "SQLNCLI11" for linked server "RemoteServer" could not UPDATE\n         table "[RemoteServer].[MyDB].[dbo].[Customer]".\nThe rowset was using optimistic concurrency and the value of a column has been\n         changed after the containing row was last fetched or resynchronized.\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我删除上的索引timestamp,查询将按照 I\xe2\x80\x99d 的预期工作。

\n\n

如何强制链接服务器查询使用悲观并发而不是乐观并发?I\xe2\x80\x99ve 已经尝试添加tabblockx查询提示,并在运行更新之前加载选择中的行并使用tabblockxholdlock。将整个事务包装在常规或分布式事务中也没有什么区别。

\n

Rem*_*anu 2

远程进行更新:

exec RemoteServer.MyDB.dbo.sp_executesql N'UPDATE Customer 
    set    FirstName = @FirstName,
       LastName = @LastName
     where  AccountNumber = @AccountNumber', 
     N'@FirstName varchar(...), @LastName varchar(...), @AccountNumber <type>',
     @FirstName, @LastName, @AccountNumber;
Run Code Online (Sandbox Code Playgroud)

必须在链接服务器上启用 RPC 和 RPC Out。