我已经设计了数据库表(在MS SQL服务器上已规范化),并为应用程序创建了一个独立的Windows前端,少数用户将使用该窗口来添加和编辑信息。我们将添加一个网络界面,以便以后在整个生产区域进行搜索。
我担心如果两个用户开始编辑同一记录,那么最后提交更新的用户将是"赢家",并且重要的信息可能会丢失。我想到了许多解决方案,但是我不确定是否会造成更大的麻烦。
不执行任何操作,并希望两个用户永远不会同时编辑同一条记录。 -可能永远不会被遮挡,但是如果会呢?
编辑例程可以存储原始数据的副本以及更新,然后在用户完成编辑后进行比较。如果它们不同,请显示用户并确认更新-将需要存储两个数据副本。
添加最后更新的DATETIME列,并在我们更新时检查它是否匹配,否则请显示差异。 -在每个相关表中都需要新列。
创建一个编辑表,该表在用户开始编辑将要检查的记录时进行注册,并防止其他用户编辑同一记录。 -需要认真考虑程序流程,以防止死锁和记录在用户退出程序时被锁定。
有没有更好的解决方案,或者我应该选择其中一种?
如果您希望不经常发生冲突,那么乐观并发可能是您最好的选择。
Scott Mitchell撰写了有关实现该模式的综合教程:
实现乐观并发
经典方法如下:
-
向每个表添加一个"锁定"的布尔字段。
-
默认情况下将其设置为false。
-
用户开始编辑时,请执行以下操作:
-
锁定行(如果无法锁定行,则锁定整个表)
-
检查您要编辑的行上的标志
-
如果标志为真,则
-
其他
-
释放锁
-
保存记录时,将标志设置回false
-first创建字段(更新时间)以存储最新更新记录
-当任何用户选择记录保存选择时间时,
比较选择时间和更新时间字段是否(更新时间)>(选择时间),这意味着另一个用户在选择记录后更新此记录
SELECT FOR UPDATE和等效项很不错,只要您在微观时间内保持该锁定,但是对于宏观而言(例如,用户已加载数据且未按"保存",则应如上所述使用开放式并发。)我一直认为自己的名字是错误的-比"最后一位作家获胜"更为悲观,后者通常是唯一考虑的其他选择。)
另一个选择是测试要更改的记录中的值是否与开始时的值相同:
1 2 3 4 5
| SELECT
customer_nm,
customer_nm AS customer_nm_orig
FROM demo_customer
WHERE customer_id = @p_customer_id |
(显示customer_nm字段,用户进行更改)
1 2 3 4 5 6 7
| UPDATE demo_customer
SET customer_nm = @p_customer_name_new
WHERE customer_id = @p_customer_id
AND customer_name = @p_customer_nm_old
IF @@ROWCOUNT = 0
RAISERROR( 'Update failed: Data changed' ); |
您不必在表中添加新列(并保持其最新状态),但是您必须创建更多详细的SQL语句并将新字段和旧字段传递给存储过程。
它还具有您不锁定记录的优点-因为我们都知道,当不应该使用记录时,记录最终将保持锁定状态。
@ Mark Harrison:SQL Server不支持该语法(SELECT ... FOR UPDATE)。
SQL Server等效项是SELECT语句提示UPDLOCK。
有关更多信息,请参见SQL Server联机丛书。
和我在一起,最好的方法是我有一个列lastupdate(时间戳数据类型)。
选择和更新时只需比较此值
该解决方案的另一个优势是,您可以使用此列来跟踪数据更改的时间。
我认为如果只创建像isLock这样的支票来更新支票是不好的。
数据库将为您执行此操作。看" select ... for update",它是专门为这种事情而设计的。它将为您提供对所选行的写锁定,然后您可以提交或回滚。