繁体   English   中英

根据 rowversion 值更新记录?

[英]Update record based on rowversion value?

我最近实施了 SQL rowversion以防止系统中出现并发问题。 更新表中的单行时,我在 where 子句中使用rowversion 到目前为止,我已经测试过,似乎是一个很好的解决方案。 现在我正在寻找一种在我的系统中实现此功能的简单方法。 这是当用户想要更新记录时运行的 SP:

CREATE PROCEDURE [dbo].[UpdateBuilding]
    @Status BIT = NULL,
    @Name VARCHAR(50) = NULL,
    @Code CHAR(2) = NULL,
    @OriginalRowVersion ROWVERSION
AS
    SET NOCOUNT ON
    SET XACT_ABORT ON
    BEGIN
        UPDATE dbo.Building
        SET Status = @Status,
            Name = @Name,
            Code = @Code,
            ActionDt = CURRENT_TIMESTAMP
        WHERE RowVersion = @OriginalRowVersion
        IF @@ROWCOUNT = 0
        BEGIN
            RAISERROR('Buildingwith code %s was modified or deleted by another user.', 16, 1, @Code);
        END;
    END;

如果我想在上面执行 SP,我需要传递所需的参数。 这是我在 SQL Management Studio 中调用 SP 的方式:

EXEC UpdateBuilding
    @Status = 1,
    @Name = "Rockefeller Center",
    @Code = 436,
    @OriginalRowVersion = 0x0000000000006955;

现在我开始研究如何在我使用 ColdFusion 与 Datatbase 通信的系统中实现这一点。 以下是有关如何使用 CF 2016 执行此过程的示例:

<cfstoredproc procedure="UpdateBuilding" datasource="#dsn#">
    <cfprocparam dbvarname="@Status" value="#trim(arguments.status)#" cfsqltype="cf_sql_bit" />
    <cfprocparam dbvarname="@Code" value="#trim(arguments.code)#" cfsqltype="cf_sql_char" maxlength="2" null="#!len(trim(arguments.code))#" />
    <cfprocparam dbvarname="@Name" value="#trim(arguments.name)#" cfsqltype="cf_sql_varchar" maxlength="50" null="#!len(trim(arguments.name))#" />
    <cfprocresult name="Result"/>
</cfstoredproc>

您可以看到所有值都与用户在表单中提交的参数一起传递。 但是,基于PK值(在我的情况下为代码列)的更新非常简单。 现在我有了二进制值,这让一切变得更加复杂。 首先,我使用 JSON 将数据发送到客户端。 在 JSON 对象中发送rowversion需要将该值转换为binary ,然后在用户提交表单时转换回来。 我想知道是否有更好的方法来实现这一目标? 理想情况下,我什至不会向用户端发送rowversion值。 我会将其保留在后端,一旦用户提交基于 PK 的表单拉行版本值,然后调用存储过程。 如果有人知道处理这种情况的好方法,请告诉我。 我以前没有使用过rowversion ,这对我来说是新的。

我使用类似的方法,其中有一列名为type int version 我通过任何读取操作将其传递给客户端。 如果客户端更新了一条记录,则它必须发回正在更新的记录的版本,并且更新将增加版本号。 但是,我的方法设置了ColdFusion锁而不是DB锁。 这是一些简化的逻辑:

function updateRecord (
    required numeric recordID,
    required struct updateData,
    required numeric version) {

    lock name="#arguments.recordID#" type="exclusive" timeout="1" throwontimeout=true {
        qRecord = queryExecute() // get the record
        if (qRecord.recordCount != 1) {
            throw();
        }
        if (qRecord.version != arguments.version) {
            throw();
        }
        // do the update using arguments.updateData
    }

}

与此相关的一个问题是,群集中的其他节点将不知道该命名锁。 您将不得不想出另一种将代码段锁定到集群中其他请求的方法。 如该线程中所述,有多种方法可以做到:

https://dev.lucee.org/t/distributed-lock-management/1004

如果这是一个问题,我敢肯定还有其他解决方案可用。

处理二进制文件并不像您想的那样困难。 检索二进制值后,将其编码为适合发送给客户端的字符串(十六进制或base64):

<cfset hexStringForClient = binaryEncode(queryName.theBinaryColumn, 'hex')>

当客户端返回编码后的字符串时, 解码回二进制并使用cf_sql_binary将其传递给数据库:

<cfset binaryValue = binaryDecode(hexStringFromClient, 'hex')>

<cfstoredproc procedure="UpdateBuilding" datasource="#dsn#">
    ... 
    <cfprocparam dbvarname="@OriginalRowVersion" value="#binaryValue#" cfsqltype="cf_sql_binary" />
    ....
</cfstoredproc>

旁注, 如您在其他线程中所述 ,开放式并发检查使用WHERE子句中的主键和行版本值:

WHERE
    Code = @Code
    AND RowVersion = @OriginalRowVersion;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM