Gen*_*zer 8 sql-server sql-server-2008-r2
我需要跟踪对象的锁定/解锁操作。在对对象(合同、合作伙伴等)进行任何操作之前,lock
会发出一个事件。动作完成后,它发出unlock
事件。
我想获取那些已锁定但尚未解锁的对象。目标是使查询快速并避免死锁。
下面是表格
create table locks (
id int identity,
name varchar(255),
lock int
)
insert into locks values('a', 1)
insert into locks values('b', 1)
insert into locks values('c', 1)
insert into locks values('d', 1)
insert into locks values('a', 0)
insert into locks values('c', 0)
insert into locks values('a', 1)
insert into locks values('b', 1)
Run Code Online (Sandbox Code Playgroud)
我使用下面的查询来反对尚未解锁的对象:
select distinct m.name from locks m
where (select COUNT(id) from locks locked
where locked.lock = 1 and locked.name = m.name)
> (select COUNT(id) from locks unlocked
where unlocked.lock = 0 and unlocked.name = m.name)
Run Code Online (Sandbox Code Playgroud)
它工作正常,结果a
,b
和d
.
我的问题是: - 我的解决方案是否足以避免死锁?如果INSERT
查询执行过程中有很多可能会出现问题吗?- 你有其他(更好的)方法来解决这个问题吗?
更新
我很抱歉没有将上下文放入问题中。上面的数据库设计不是为了替换数据库锁定。
我们有一个外部系统,我们从我们的系统中调用它。它需要在对对象(可以是合同或合作伙伴)执行每个操作之前在他们的系统上调用lock
和unlock
方法。
最近,我们遇到了服务器崩溃的情况,我们不得不重新启动它。不幸的是,已经调用的正在运行的进程lock
没有机会调用unlock
释放对象,因此当我们的系统再次连接到外部时会导致其他几个问题。
因此,我们希望提供跟踪每个lock
调用的功能。重新启动服务器后,我们将调用unlock
先前锁定的对象。
感谢 Remus Rusanu 指出我的问题是使用原型DDL。这是我第一次在 DBA 上发布问题,我很抱歉没有阅读常见问题解答。
谢谢
Rem*_*anu 11
目标是使查询快速并避免死锁。
这是一个不切实际的目标。死锁由获取锁的应用程序决定,并且不受您如何实现锁定的控制。最好的方法是检测死锁。
将锁实现为记录是有问题的。行持续存在并且您会在应用程序崩溃时泄漏锁,即使实现是完美的。用applocks做锁。它们具有清晰的事务语义,并且引擎会检测到死锁。
然而,看着你想达到什么样的,是不可能的,你需要的锁都。您正在描述一个队列(选择下一个可用于处理的项目并避免冲突 => 队列,而不是锁定)。阅读使用表作为队列。
至于您的具体实现(使用保留锁定历史的表),我必须诚实:这是一场灾难。从表设计开始完全不适合预期用途:您按名称查询,但表是没有索引的堆。它有一个没有明显原因的标识列。您可能会回复说它只是一个“伪代码”表,但这是 DBA.SE,您不要在此处发布不完整的 DDL!
但更重要的是,实现并没有实现锁定!有没有阻止两个用户从“锁定”同样的对象两次。您的“锁定”完全依赖于调用者神奇的正确行为。即使是编写得最好的应用程序也无法使用这种锁定,因为无法以原子方式检查和获取锁定。两个用户可以检查,得出'a'被解锁的结论,并同时插入('a', 1)
记录。在非常至少,你需要的唯一约束。这当然会破坏“计数锁定与解锁以确定状态”的语义。
很抱歉,但这是 F 级实现。
更新
因此,我们希望提供跟踪每个锁调用的功能。重新启动服务器后,我们将对先前锁定的对象调用 unlock。
无需与远程系统进行两阶段提交分布式事务,您所能做的就是“尽力而为”,因为在第三方系统上编写“解锁”和实际调用“解锁”之间存在许多竞争条件. 作为最大的努力,这是我的建议:
创建一个简单的表来跟踪锁:
CREATE TABLE locks (name VARCHAR(255) NOT NULL PRIMARY KEY);
在调用lock
insert the lock into your table并 commit 之前。
unlock
删除锁并提交后unlock
每一行,然后删除该行。只有在所有挂起的锁都被“解锁”之后,您才能恢复应用程序的正常功能。我提出这个建议是因为桌子会保持很小。在任何时候,它都只包含当前的、活动的锁。它不会因为庞大的体型而引起恶心并在以后引起问题。看到什么被锁定是微不足道的。
当然,此实现不提供有关由谁和何时锁定的内容的审计历史记录。如果需要,您可以将其添加为不同的表,您只将事件(锁定或解锁)插入其中,而从不查询以找出“孤立”锁。
您仍然必须准备在启动期间调用“解锁”失败,因为您不能保证您的系统在调用之后unlock
但在删除行之前不会崩溃(换句话说,您的表和第三方系统已经分开并且有不同的真相的版本)。同样,你不能阻止这种W / O分布式事务和我永远不会叫的DTC。
归档时间: |
|
查看次数: |
2169 次 |
最近记录: |