簡體   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