簡體   English   中英

嘗試通過 DAO 記錄集更新記錄時出現運行時錯誤 3197

[英]Run-time error 3197 when attempting to update record via DAO recordset

我有一個 Microsoft Access 2016 應用程序,目前使用 SQL Server 2019 后端運行。 我在嘗試使用 recordset.update 將更改保存到產品表中的特定記錄時遇到問題。 我完全是自學成才,並且已經使用 vba 編碼大約 18 個月,過去曾遇到過位字段的這個問題,但這次我看不出是什么原因造成的。

錯誤:

錯誤 3197:microsoft access 數據庫引擎停止了進程,因為您和另一個用戶試圖同時更改相同的數據

我嘗試過的事情:

  1. 該表有一個主鍵

  2. 此表中的大多數記錄允許我編輯和更新更改(隨機選擇不起作用)

  3. 所有位字段的默認值都設置為 0

  4. 我嘗試只更新眾多字段中的 1 個以查看這是否會影響結果,它不會,無論我是僅編輯 integer 字段還是多個混合類型,它仍然會發生

  5. 我可以使用 SQL 查詢(通過或通過 Access 查詢設計器)直接更改此表中任何字段的值

  6. 我無法直接通過表更改這些記錄上的任何值(其他都可以)(使用 ms 訪問表視圖,我得到 Drop Changes / Save to clipboard 對話框)

  7. 盡管在通過表單使用此特定 function 時確實會發生這種情況,但即使直接通過 vba 編輯器中的立即 window 運行代碼,我也會收到相同的錯誤。 但是我確保表單使用的記錄鎖定是沒有鎖的。

  8. 默認打開模式設置為共享(對於 db,通過選項 -> 客戶端設置)

  9. 默認記錄鎖定是無鎖(對於數據庫,通過選項 -> 客戶端設置)

  10. 當前使用行級鎖定(對於數據庫,通過選項-> 客戶端設置)

作為參考,代碼足夠簡單明了:

Dim dbs As DAO.Database
Dim productRS As DAO.Recordset

Set dbs = CurrentDb
Set productRS = dbs.OpenRecordset("Select * From tblProducts WHERE ProductID = " & ProductID, dbOpenDynaset, dbSeeChanges)

With productRS
.Edit
!Name = someName
.Update
End With

rs.close
dbs.close

set rs = nothing
set dbs = nothing

我還有一個 RecordTimestamp 字段 (datetime2(7)),它使用 GetDate() 作為記錄的默認值,並且從項目一開始就是這樣設置的,這讓我認為這不是這個字段的問題。 但是我不完全理解 sqlserver 和訪問如何准確地記住/確定記錄是否被鎖定/正在更新,或者是否有辦法清除所有這些掛起/不存在的鎖。

如果有人能想到會導致此問題的事情,請提前致謝。

您需要將所謂的 rowverison 列添加到數據庫中。 現在,也許歷史上最偉大的獎項頒給了人們,因為他們稱之為“時間戳”列,因此是最糟糕的名字!

原因當然是時間戳列與日期時間的關系為零,並且是 SQL 服務器中的列與日期時間列的巨大差異。

時間戳數據類型列不是日期時間列

這是一個您永遠不會以任何方式和任何上下文設置、觸摸或修改的列,您或任何代碼。 而且您永遠不必為此行版本列設置默認值,並且您永遠不會嘗試觸摸或修改此列 - 其中包括您的代碼、sql 服務器端代碼,還包括沒有為這個時間戳列,當然是您如何在 Access 中創建和獲取 ROWVERSION 列。

它是一個沒有默認值的列。 它實際上是一個帶有校驗和值的二進制 blob。

如果不是 1000% 清楚,是 100%?

您被告知添加所謂的 ROWVERSION 列。 要創建這樣的列,您需要創建一個 TIMESTAMP 數據類型的列。 這不是日期時間列,您不能創建日期時間列,也不能為此行版本列設置默認值。 您也不能采用 datetime(2)7 格式的一些 datetime 列。

當然,任何浮點列也需要默認值 0,除了具有該默認值之外,它們不應該是 null。

最后但並非最不重要的:

如果該列中的浮點數值已設置為無法訪問,則可能會出現路由問題。

因此,當訪問嘗試檢查/測試記錄是否已更改時,它會進行 FIELD BY FIELD 數據比較,但它會失敗。

但是,引入 ROWVERSION 列(您使用數據類型時間戳),然后訪問逐列“test”放棄此列,然后在一次操作中使用該 TIMESTAMP 列。 因此不再需要逐列比較,因此不再需要浮點數和由於舍入比較等內容。

如前所述,毫無疑問,TIMESTAMP 數據類型的名稱確實因最糟糕的名稱而獲得了世界最佳獎。 值得稱贊的是,較新的文檔將時間戳數據類型列稱為 ROWVERSION,但損害已經發生並且已經發生。 我們將永遠生活在這個爛攤子中。

因此,非常重要的是要記住,這個數據類型 = 時間戳的“rowversion”列與日期時間有零零零。

因此,不能將日期時間列與時間戳(又名:行版本)列混淆,它們是截然不同的。

所以要解決這個問題,你會在 SO 和其他板上閱讀每周的帖子。 這里的簡單建議是為您添加一個時間戳列,您現在意識到它與時間或日期無關,或者實際上與日期時間列無關。

如前所述,rowversion 列沒有默認值,並且您從未在 sql 服務器或事物的訪問端設置任何此類默認值。 您不必這樣做,實際上通常不能修改此行版本列。 而且,您沒有設置默認值,它只是一個二進制 blob 列,用於確定記錄是否已更改。

並且如前所述,擁有這樣的行版本列允許訪問放棄,並且不必逐列比較以確定記錄是否已更改。

所以這個周刊是過去 20 年的另一篇文章?

那20年的解決方案呢?

你確保有一個PK。

您確保默認位字段為 0 - 不允許 null。

您還應該確保數字(浮動/實數)列也具有默認值 0。

最后但並非最不重要的是,您還添加了一個rowversion列,您需要選擇“timestamp”作為數據類型來獲取並獲取SQL服務器中的rowversion列。

如前所述,此列的名稱和類型與日期時間列的關系為零。

那么,就像其他頻繁發布的帖子一樣——過去 20 年來每周大約 1-2 次?

嘗試根據多年的建議添加時間戳列,以解決此問題。

無需使用記錄集進行簡單更新。 只需使用Database.Execute

dbs.Execute "Update tblProducts " & _
    "Set Name = '" & someName & "' " & _
    "WHERE ProductID = " & ProductID & ";"

Debug.Print dbs.RecordsAffected & " record(s) affected."

如果您堅持使用記錄集執行更新,請嘗試將 select 語句從

Select * From tblProducts ...

Select Name From tblProducts ...

為什么要費心從服務器拖回您不打算使用的數據?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM