运行-尝试通过 DAO 记录集更新记录时出现错误 3197
Run-time error 3197 when attempting to update record via DAO recordset
我有一个 Microsoft Access 2016 应用程序,目前 运行 一个 SQL Server 2019 后端。我在尝试使用 recordset.update 将更改保存到我的产品 table 中的特定记录时遇到问题。我完全是自学成才,用 vba 编码大约 18 个月,过去遇到过这个位域问题,但这次我看不出是什么原因造成的。
错误:
错误 3197:Microsoft Access 数据库引擎停止了进程,因为您和另一个用户试图同时更改相同的数据
我尝试过的事情:
table有一个主键
此table中的大多数记录允许我编辑和更新更改(随机选择无效)
所有位字段的默认值都设置为 0
我试过只更新许多字段中的一个,看看是否会影响结果,但不管我是只编辑一个整数字段,还是多个混合类型,它都不会, 它仍然发生
我可以使用 SQL 查询(通过或通过 Access 查询设计器)直接更改此 table 中任何字段的值
我无法通过 table 直接更改这些记录的任何值(其他都可以)(使用 ms access table 视图,我得到了 Drop Changes / Save to剪贴板对话框)
尽管通过表单使用此特定功能时确实会发生这种情况,即使 运行 代码直接通过 vba 编辑器中的即时 window,也是如此,我犯了同样的错误。但是我确保了表单使用的记录锁定是没有锁的。
默认打开模式设置为共享(对于数据库,通过选项 -> 客户端设置)
默认的记录锁定是无锁(对于数据库,通过选项 -> 客户端设置)
当前正在使用行级锁定(对于数据库,通过选项 -> 客户端设置)
供参考,代码足够简单明了:
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 和访问 remember/determine 如果一条记录被 locked/being 更新,或者如果有一种方法我可以清除所有这些 pending/non-existant 锁。
如果有人能想到会导致此问题的原因,请提前致谢。
不需要使用记录集进行简单的更新。只需使用 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 ...
为什么要从您不打算使用的服务器拖回数据?
您需要将所谓的 rowverison 列添加到数据库中。现在,历史上最伟大的奖项可能会授予那些将其称为“时间戳”列的人们,因此使用最糟糕的名称!
原因当然是时间戳列与日期时间的关系为零,并且是 SQL 服务器中日期时间列与日期时间列的巨大差异。
时间戳数据类型列不是日期时间列
这是一个您永远不会以任何方式和任何上下文设置、触摸或修改的列,您或任何代码。而且您永远不必为此行版本列设置默认值,并且您永远不会尝试触摸或修改此列 - 这包括您的代码,sql 服务器端代码,还包括没有此时间戳列的默认设置,这当然是您在 Access 中创建和获取 ROWVERSION 列的方式。
这是一个没有默认值的列。它实际上是一个带有校验和值的二进制 blob。
即使不是 1000% 也要 100% 清楚?
您被告知添加所谓的 ROWVERSION 列。要创建这样一个列,您需要创建一个 TIMESTAMP 数据类型的列。这不是日期时间列,您不能创建日期时间列,也不能为此行版本列设置默认值。
您也不会采用 datetime(2)7 格式的日期时间列。
当然,任何浮点数列也需要默认值 0,除了具有该默认值外,它们不应为空。
最后但同样重要的是:
如果该列中的浮动数值已设置为无法访问,则可能会出现路由问题。
因此,如果记录已更改,当访问尝试 check/test 时,它会执行 FIELD BY FIELD 数据比较,但失败。
但是,引入 ROWVERSION 列(您使用数据类型时间戳),然后访问逐列“测试”放弃此列,然后在一次操作中使用该 TIMESTAMP 列。因此不再需要逐列比较,因此不再需要像浮点数和舍入比较之类的东西。
如前所述,毫无疑问,TIMESTAMP 数据类型的名称确实获得了世界上最差名称的最佳奖项。值得赞扬的是,较新的文档将时间戳数据类型列称为 ROWVERSION,但损害已经并且已经造成。我们将永远生活在这种混乱中。
因此,请务必记住数据类型 = timestamp 的“rowversion”列与 datetime 有零零零的关系。
因此,不能将日期时间列与时间戳(又名:行版本)列混淆,它们有很大的不同。
因此,要解决此问题,您将在 SO 和其他论坛上每周阅读 posts。此处的简单建议是添加一个时间戳列,您现在意识到它与时间或日期无关,或者实际上与日期时间列无关。
如前所述,该 rowversion 列没有默认值,并且您从未在 sql 服务器或事物的访问端设置任何此类默认值。您不必这样做,事实上作为一般规则不能修改此行版本列。而且,您没有设置默认值,它只是一个二进制 blob 列,用于确定记录是否已更改。
如前所述,拥有这样的行版本列允许访问放弃,而不必逐列比较以确定记录是否已更改。
所以这个每周是过去 20 年的另一个 post?
这 20 年的解决方案是什么?
你确定有PK。
您确保将位字段默认为 0 - 不允许为空。
您还应确保数字 (floating/real) 列也具有默认值 0。
最后但同样重要的是,您还添加了一个rowversion列,其中您需要选择“timestamp”作为数据类型来获取并获取SQL服务器中的一个rowversion列。
如前所述,列的名称和类型与日期时间列的关系为零。
所以,就像其他经常 post 的人一样 - 在过去 20 年里每周大约 1-2 次?
尝试根据多年以来的建议添加时间戳列来解决此问题。
我有一个 Microsoft Access 2016 应用程序,目前 运行 一个 SQL Server 2019 后端。我在尝试使用 recordset.update 将更改保存到我的产品 table 中的特定记录时遇到问题。我完全是自学成才,用 vba 编码大约 18 个月,过去遇到过这个位域问题,但这次我看不出是什么原因造成的。
错误:
错误 3197:Microsoft Access 数据库引擎停止了进程,因为您和另一个用户试图同时更改相同的数据
我尝试过的事情:
table有一个主键
此table中的大多数记录允许我编辑和更新更改(随机选择无效)
所有位字段的默认值都设置为 0
我试过只更新许多字段中的一个,看看是否会影响结果,但不管我是只编辑一个整数字段,还是多个混合类型,它都不会, 它仍然发生
我可以使用 SQL 查询(通过或通过 Access 查询设计器)直接更改此 table 中任何字段的值
我无法通过 table 直接更改这些记录的任何值(其他都可以)(使用 ms access table 视图,我得到了 Drop Changes / Save to剪贴板对话框)
尽管通过表单使用此特定功能时确实会发生这种情况,即使 运行 代码直接通过 vba 编辑器中的即时 window,也是如此,我犯了同样的错误。但是我确保了表单使用的记录锁定是没有锁的。
默认打开模式设置为共享(对于数据库,通过选项 -> 客户端设置)
默认的记录锁定是无锁(对于数据库,通过选项 -> 客户端设置)
当前正在使用行级锁定(对于数据库,通过选项 -> 客户端设置)
供参考,代码足够简单明了:
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 和访问 remember/determine 如果一条记录被 locked/being 更新,或者如果有一种方法我可以清除所有这些 pending/non-existant 锁。
如果有人能想到会导致此问题的原因,请提前致谢。
不需要使用记录集进行简单的更新。只需使用 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 ...
为什么要从您不打算使用的服务器拖回数据?
您需要将所谓的 rowverison 列添加到数据库中。现在,历史上最伟大的奖项可能会授予那些将其称为“时间戳”列的人们,因此使用最糟糕的名称!
原因当然是时间戳列与日期时间的关系为零,并且是 SQL 服务器中日期时间列与日期时间列的巨大差异。
时间戳数据类型列不是日期时间列
这是一个您永远不会以任何方式和任何上下文设置、触摸或修改的列,您或任何代码。而且您永远不必为此行版本列设置默认值,并且您永远不会尝试触摸或修改此列 - 这包括您的代码,sql 服务器端代码,还包括没有此时间戳列的默认设置,这当然是您在 Access 中创建和获取 ROWVERSION 列的方式。
这是一个没有默认值的列。它实际上是一个带有校验和值的二进制 blob。
即使不是 1000% 也要 100% 清楚?
您被告知添加所谓的 ROWVERSION 列。要创建这样一个列,您需要创建一个 TIMESTAMP 数据类型的列。这不是日期时间列,您不能创建日期时间列,也不能为此行版本列设置默认值。 您也不会采用 datetime(2)7 格式的日期时间列。
当然,任何浮点数列也需要默认值 0,除了具有该默认值外,它们不应为空。
最后但同样重要的是:
如果该列中的浮动数值已设置为无法访问,则可能会出现路由问题。
因此,如果记录已更改,当访问尝试 check/test 时,它会执行 FIELD BY FIELD 数据比较,但失败。
但是,引入 ROWVERSION 列(您使用数据类型时间戳),然后访问逐列“测试”放弃此列,然后在一次操作中使用该 TIMESTAMP 列。因此不再需要逐列比较,因此不再需要像浮点数和舍入比较之类的东西。
如前所述,毫无疑问,TIMESTAMP 数据类型的名称确实获得了世界上最差名称的最佳奖项。值得赞扬的是,较新的文档将时间戳数据类型列称为 ROWVERSION,但损害已经并且已经造成。我们将永远生活在这种混乱中。
因此,请务必记住数据类型 = timestamp 的“rowversion”列与 datetime 有零零零的关系。
因此,不能将日期时间列与时间戳(又名:行版本)列混淆,它们有很大的不同。
因此,要解决此问题,您将在 SO 和其他论坛上每周阅读 posts。此处的简单建议是添加一个时间戳列,您现在意识到它与时间或日期无关,或者实际上与日期时间列无关。
如前所述,该 rowversion 列没有默认值,并且您从未在 sql 服务器或事物的访问端设置任何此类默认值。您不必这样做,事实上作为一般规则不能修改此行版本列。而且,您没有设置默认值,它只是一个二进制 blob 列,用于确定记录是否已更改。
如前所述,拥有这样的行版本列允许访问放弃,而不必逐列比较以确定记录是否已更改。
所以这个每周是过去 20 年的另一个 post?
这 20 年的解决方案是什么?
你确定有PK。
您确保将位字段默认为 0 - 不允许为空。
您还应确保数字 (floating/real) 列也具有默认值 0。
最后但同样重要的是,您还添加了一个rowversion列,其中您需要选择“timestamp”作为数据类型来获取并获取SQL服务器中的一个rowversion列。
如前所述,列的名称和类型与日期时间列的关系为零。
所以,就像其他经常 post 的人一样 - 在过去 20 年里每周大约 1-2 次?
尝试根据多年以来的建议添加时间戳列来解决此问题。