我读得越多,就越困惑,所以希望有人能帮上忙。我有一个复杂的数据库设置,有时会在更新时产生错误:
“并发冲突: UpdateCommand影响了预期的1条记录中的0条”
我有时会说,因为我不能重新创造条件来持续地触发它。我有一个远程mySQL数据库,通过DataSource向导连接到我的应用程序,该向导生成数据集、表和链接的DataTableAdapters。
我的阅读表明,当试图更新同一记录的数据库有多个打开连接时,就会发生此错误?这不应该发生在我的例子,因为唯一的更新是从我的应用程序顺序。
我想知道这是否与从后台工作人员运行更新有关?例如,我把我的表更新放在一个中:
Gi_gamethemeTableAdapter.Update(dbDS.gi_gametheme)
Gi_gameplaystyleTableAdapter.Update(dbDS.gi_gameplaystyle)
Gi_gameTableAdapter.Update(dbDS.gi_game)然而,这些程序在后台工作人员中连续运行,因此对此不确定。主线程也在等待它完成,在启动之前或之后没有其他的db操作。
我读过有关进入dataset designer视图的文章,在datatableadapter > advanced中选择“配置”,并将“使用乐观并发性”设置为false。这可能是可行的(很难说,因为错误看起来是随机的),但是,我想要避免的缺点是:
在数据库更新等方面,我恐怕不是在代码级别,而是依赖于Visual向导。更改堆栈也为时已晚(例如无法更改为实体框架等)。
所以我的问题是:
谢谢
发布于 2021-05-25 20:42:12
当您有将数据下载到数据中的tableadapters时,可以将它们配置为乐观并发。
这意味着对于像以下这样的桌子:
Person
ID Name
1 John它们可能会生成一个更新查询,例如:
UPDATE Person SET Name = @newName WHERE ID = @oldID AND Name = @oldName(实际上,它们比这更复杂,但这就足够了)
Datatable跟踪原始值和当前值;您下载1/ "John“,然后将名称更改为"Jane",您(或tableadapter)可以问DT原始值是什么,它会说”John“。
datatable还可以将此值输入更新查询,这就是我们如何检测“如果有其他什么东西在我们拥有时更改了行”,即并发冲突。
当我们下载时,行是"John“,我们把它编辑成"Jane",然后去保存。但是其他人也加入了,并把它改成了“乔”。我们的更新将失败,因为当我们下载它时,名称不再是"John“(而且我们仍然认为它是)。使用具有AND Name = @oldName的更新查询的tableadapter,并将@oldName参数设置为原始值somedatarow["Name", DataRowVersion.Original].Value (即“约翰”)我们导致更新失败。这是一件有用的事情;大多数情况下他们会成功,因此我们可以机会主义地希望我们的用户能够更新我们的db,而不需要在某些UI中打开行时进入锁定行。
解决不起作用的情况通常是编写某种策略的案例:
现在你可能坐在那里说“但是没有其他人改变我的数据库”--不过,如果数据库在一次保存中更改了一些值,而且数据集中没有最新的值,我们仍然可以得到它。
tableadapter wizardd中还有另一个选项--“刷新数据集”--它应该在修改后运行一个select,以导入任何最新的数据库计算值(比如auto主键或触发器/默认值/等等)。有些查询(如INSERT INTO Person(Name) VALUES(@name) )应该在其末尾单独标记一个SELECT * FROM PERSON WHERE ID = last_inserted_id(),以检索最新的值。
除了“刷新数据集”无效 :/
所以,虽然我不能确切地告诉你为什么会得到你的简历异常,但我希望解释它们的原因,并指出有时会有错误导致它们(插入新记录,计算出的ID不会被撤回,编辑最近的记录,更新失败,因为数据不是新鲜的),希望能为您提供找到问题所需的武器:当您得到一个问题时,保持应用程序在断点上停止并检查数据仓库:查看正在运行的查询,查看正在作为参数的原始/当前值-使用允许您声明所需版本的项索引器的重载。检查该行持有的原始值和当前值,并查看DB。
所有这些都会有不匹配的地方,从而解释了为什么更新了0条记录??数据库以"Joe“作为名称,174354325作为ID,您的数据方式将"John”作为原始名称,-1作为ID (它从未刷新),因此WHERE子句找到了0条记录。
发布于 2021-05-25 20:41:34
有些表将包含一个标记为[ConcurrencyCheck]或[TimeStamp] 并发令牌的字段。
更新记录时,生成的SQL将包括一个WHERE [ConcurrencyField]='Whatever the value was when the record was retrieved'。
如果该记录是由另一个线程或进程或当前线程以外的其他内容更新的,那么您的更新将返回0条更新的记录,而不是预期的1(或更多)记录。
看你怎么办?首先,在代码周围放置一个尝试/捕获(DbConcurrencyException)。然后,您可以重新读取违规记录,并尝试再次更新它。
https://stackoverflow.com/questions/67695121
复制相似问题