我正在尝试在 SQL 中实现一个简单的行锁,而没有事务的开销,甚至没有版本号的“麻烦” 我的暂定解决方案如下:
query = 'UPDATE my_table SET lock_field = 1 WHERE lock_field = 0 AND user_id = 17'
if (query.execute() == 1){
// We own the lock, modify record at will
// Finally: 'UPDATE my_table SET lock_field = 0 WHERE user_id = 17'
} else {
// Somebody else owns the lock... or the user_id does not exist...
}
我的问题是:这段代码安全吗?它是否保证只有一个“客户端”可以拥有锁?
我们可以假设所有客户端都在合作,没有人会在没有首先获得“锁”的情况下以任何方式修改记录
附加信息是,获取锁允许客户端处理/与该表和其他表甚至其他数据库中的 user_id 进行交互。如果客户端失败,可能会存在许多不一致之处,需要在手动解锁记录之前进行半手动清理。例如后自动解锁超时不安全
我的困惑源于无法在谷歌中找到类似的示例,这些示例看起来比事务甚至带有版本号的乐观锁定简单得多
这种方法是安全的,因为它保证没有两个客户端可以同时获取“锁”。问题是这在实践中是不够的,因为这不能保证至少一个客户端能够获取锁;数据库将在某个时刻停止做有用的工作。请注意,数据库根本不执行任何操作,支持上述保证。
原因是没有办法保证锁会被解锁。考虑事件的顺序
1. `SET lock_field = 1`
2. `query.execute() == 1` is true
3. OutOfMemoryException
4. Thread raised exception within exception, process aborted, destructor did not run
5. The row is now locked forever
无法判断锁定该行的客户端是否已消失、中止、网络连接重置、陷入无限循环,或者只是由于错误而未解锁。严格来说,你提到的保证是成立的,但无法进行任何有用的工作。
解决这个问题的唯一方法就是猜测客户已经走了。希望客户真的消失了。但这样我们就无法确定受锁保护的数据是否处于一致状态。
长话短说:不,这样的计划在实践中行不通。不要试图让它们发挥作用;他们不。数据库本身完全可以保证事务隔离,同时提供前进的保证。