当记录被锁定时,我该如何安全地退出DBMS?

3
我是一名业余程序员,但已经有一段时间了。我正在编写一个小型文档管理应用程序(使用c#),用于工作中。当用户打开记录时,我会更新它以指示当前正在编辑。

我不确定的是如何确保在应用程序意外退出时(例如计算机意外关闭)数据库得到更新?此外,当应用程序通过用户关闭计算机退出时,应该如何更新它?我只想确保在没有人查看记录时不会出现记录被标记为锁定的情况。

5个回答

2
这是 SQL Server 通常的操作方式。开发者发出的“记录锁”与客户端-服务器架构无关。你把共享文件架构和客户端-服务器架构混淆了。
确保表格有一个时间戳列(由数据库引擎自动更新)。
读取要编辑的行。将该行中的时间戳放入变量中。
更新语句如下:
update myTable
set col = {some value}
where id = {your id}
AND
timestampcolumn = {the timestamp the row had when you read it in}

如果在您阅读记录之后,其他人对该行进行了更改,则时间戳将不同,没有记录会符合您的WHERE子句条件,因此您的更新操作将失败。 然后,您可以决定如何处理。

当您使用SQL-Server(或Oracle或任何真正的客户端-服务器架构)时,您可以随时断开客户端PC的连接,而不会对服务器产生任何负面影响。


如果你想要搜索的话,这被称为“乐观锁定”。 - Polyfun
乐观并发是一回事,但确实存在真正的情况,需要在记录级别上公开和跟踪“锁定”(注意:不是RDMBS锁定)。此外,据我所知,“rowversion”现在比“timestamp”更常用(尽管在SQL服务器中它们是同义词)。 - Marc Gravell
@ShellShock - 它是乐观的并发 - 那里没有任何“锁定”。 - Marc Gravell
谢谢Tim。这很有道理。我总是试图用最困难的方式解决问题 :) - Adam
@Marc:我同意你的观点,有时确实需要行级悲观锁定。但是在 SQLServer 中,行级悲观锁定(与页面级悲观锁定不同)实际上是不可能的,据我所知;在繁忙的多用户场景中,如果用户争夺相同的页面而不是相同的行,则页面锁定是不可行的,因为太多人需要等待。https://dev59.com/AXM_5IYBdhLWcg3wMgEF - Tim
此外,当应用程序通过向记录中写入一个值来设置伪锁(与数据库引擎设置锁不同),表示该记录正在使用时,这实际上只是一个粗略的信号量,可能会被高并发场景或其他应用程序打破,这些应用程序可能不知道或不遵守约定。 - Tim

1
在C#中,你可以使用try-catch-finally代码块,并在finally中进行清理工作(无论发生什么情况都会执行)。
你可以通过创建一个实现IDisposable的类来实现类似的功能,当调用disposing方法时,该类获得锁定并释放它。每当你使用这个获取锁的类时,把它放在using块中即可。
using (RecordLockingThing myThing = new RecordLockingThing())
{
    //DoStuff
}
//Now myThing is out of scope, and will have been disposed.

请确保您的RecordLockingThing在处理方法中正确且安全地释放锁。

另一种策略可能是不标记要锁定的记录,而是将它们标记为已编辑(或增加修订号)。然后,您可以允许多个人打开记录。当有人提交编辑时,请让他们同时提交修订号,如果匹配,则提交编辑并增加修订版号,如果不匹配,则报告“空中碰撞”,然后丢弃编辑(不太友好),或尝试让用户合并记录。

如果相对于读取而言编辑较少,第二种策略在实践中将更有用,因为您永远不会阻止用户至少查看记录,并且不存在孤立锁的风险。


0

为了处理意外关机问题,我通常会给每个逻辑锁定一个过期时间;这可能意味着(例如)你需要一个 LockOwnerId 和一个 LockExpiry 列,但通常不是问题。如果用户仍然在屏幕上,你的应用程序可以随时 延长 锁定时间,但这意味着如果计算机突然断开网络连接,记录将在几分钟内自动变为可用状态。另一个选择是允许关键用户强制解除锁定。

关于用户终止应用程序的问题;只需跟踪您所拥有的锁并删除它们 ;p


0

我曾经在一个DMS应用程序中遇到过类似的问题,在服务器端我使用了一个会话对象,即活动用户的集合,每个客户端每5分钟更新一次会话对象。因此,如果一行被锁定并且锁定它的用户不再在会话对象中,则我会释放它。为了解锁,我在服务器端运行一个后台线程,每分钟扫描一次锁定的行。


0

我很惊讶没有人提到sp_getapplock及其类似功能。只要您保持与服务器的单个连接打开(并且锁由Session拥有而不是Transaction),则锁将得以维护。如果连接中断(例如客户端机器崩溃),则与SQL Server中的所有内部锁一样,锁将被释放。

本质上,这是一种使SQL Server为您的应用程序目的使用其内部锁定机制的方法。

正如我所说,它的一个小问题是您必须保持与服务器的连接打开。因此,对于最多50个客户端而言可能更合适,而不是涉及数千个客户端的情况。我还要补充另一个警告-我尚未使用这些功能构建生产系统。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接