MySQL:如何锁定表并启动事务?

Mal*_*ous 4 mysql locking transactions data-consistency

TL; DR - MySQL不允许您锁定表并同时使用事务.有没有办法解决?

我有一个MySQL表,我用来缓存(慢)外部系统的一些数据.数据用于显示网页(用PHP编写).每隔一段时间,当缓存数据被认为太旧时,其中一个网络连接应该触发缓存数据的更新.

我必须处理三个问题:

  • 其他客户端将在我更新时尝试读取缓存数据
  • 多个客户端可能会认为缓存数据太旧并尝试同时更新缓存数据
  • 执行工作的PHP实例可能会在任何时候意外终止,并且数据不应该被破坏

我可以通过使用事务解决第一个和最后一个问题,因此客户端将能够读取旧数据,直到事务提交,他们将立即看到新数据.任何问题都只会导致事务回滚.

我可以通过锁定表来解决第二个问题,这样只有一个进程有机会执行更新.当任何其他进程获得锁定时,他们将意识到他们已被击败,无需更新任何内容.

这意味着我需要锁定表启动事务.根据MySQL手册,这是不可能的.启动事务会释放锁,并锁定表会提交任何活动事务.

有没有办法绕过这个,还是有另一种方式完全实现我的目标?

Tom*_*lka 5

这意味着我需要锁定表并启动事务

这是你如何做到的:

SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅mysql doc


sym*_*ean 4

如果是我,我会使用MySQL 中的咨询锁定功能来实现用于更新缓存的互斥体和用于读隔离的事务。例如

begin_transaction(); // although reading a single row doesnt really require this
$cached=runquery("SELECT * FROM cache WHERE key=$id");
end_transaction();

if (is_expired($cached)) {
   $cached=refresh_data($cached, $id);
}
...

function refresh_data($cached, $id)
{
 $lockname=some_deterministic_transform($id);
 if (1==runquery("SELECT GET_LOCK('$lockname',0)") {
    $cached=fetch_source_data($id);
    begin_transaction();
    write_data($cached, $id);
    end_transaction();
    runquery("SELECT RELEASE_LOCK('$lockname')");
 }
 return $cached; 
}
Run Code Online (Sandbox Code Playgroud)

(顺便说一句:如果您尝试使用持久连接,可能会发生不好的事情)