为特定属性部分锁定 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()
将释放先前设置的锁。
我实际上也使用这种方法来锁定我们的应用程序缓存(即使它不使用数据库),所以它也有数据库之外的范围。
将表迁移到 innodb(如果尚未完成)并使用事务。
我们想要防止数据库中出现一些并发问题(我们使用事件源并希望在事件有效的情况下将事件插入事件日志)。
问题是我们需要检查是否允许某个操作(需要 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()
将释放先前设置的锁。
我实际上也使用这种方法来锁定我们的应用程序缓存(即使它不使用数据库),所以它也有数据库之外的范围。
将表迁移到 innodb(如果尚未完成)并使用事务。