为特定属性部分锁定 table

Partially lock a table for a specific attribute

我们想要防止数据库中出现一些并发问题(我们使用事件源并希望在事件有效的情况下将事件插入事件日志)。

问题是我们需要检查是否允许某个操作(需要 SELECT 查询和 php 中的一些检查)然后 运行 一个 INSERT 查询实际上执行操作。

现在,我们可以简单地锁定整个 table,进行检查,如果成功,则插入(并移除锁)。

这个问题是它锁定了整个 table,这太过分了(会有很多关于这个 table 的查询)。我想做的是锁定所有想要为特定 object_id 执行此 select 插入操作的查询,但允许对所有其他 object_id's 的查询继续,就好像有没有锁。

我搜索了一下,没有找到锁定属性命令。 innoDB 中似乎有一个 lock row 命令,但这并不是我们真正想要的(我想我不是 100% 确定它的作用)。 我们当然可以尝试手动处理锁(检查在一些单独的锁 table 中是否存在带有 object_id 的列并等待直到有 none),但这感觉有点可疑并且容易出错。

所以,真正的问题是:是否可以为列的特定值 (object_id) 锁定 table? 如果锁只针对特定的 SELECT-INSERT 查询,而不是针对独立的 SELECT 查询,那就太棒了,但现在这并不重要。

考虑使用 GET_LOCK();

手动任意锁定

选择一个特定于您要锁定的行的名称。例如'xxx_event_id_y'。其中 'xxx' 是特定于过程的字符串,table 和 'y' 是事件 ID。

调用SELECT GET_LOCK('xxx_event_id_y',30)锁定名称'xxx_event_id_y'..它将return 1并在名称可用时设置锁定,或者return 0如果锁定30秒后不可用(第二个参数为超时)。

完成后使用DO RELEASE_LOCK('xxx_event_id_y')

注意;您必须在要等待的每个事务中使用相同的名称,并且在事务中再次调用 GET_LOCK() 将释放先前设置的锁。

GET_LOCK() docs

我实际上也使用这种方法来锁定我们的应用程序缓存(即使它不使用数据库),所以它也有数据库之外的范围。

将表迁移到 innodb(如果尚未完成)并使用事务。