PDO 锁定 Table 行 INNODB

PDO Lock Table Row INNODB

我有一个 table 存储敏感数据的地方,需要小心,只有一个会话能够 read/write 在特定行上。

我的 table 有 2 列 id (int) 主要 金额(整数)指数

所以我想锁定 table 但只有一行 像

LOCK TABLEROWS `mytable` WRITE WHERE `id` = 1

我使用 pdo 和 startTransaction 不会阻止其他会话到 read/write 由于那个时间

我阅读了 InnoDB 文档,但没有读到 运行

编辑:

$_PDO->exec('START TRANSACTION');
$_PDO->query('SELECT * FROM `currency` WHERE `id` = '.$userid.' FOR UPDATE');  
//maybe do update or not check if
$_PDO->exec('COMMIT');

这就是我需要做的吗?

您显示的示例将导致其他正在执行 SELECT...FOR UPDATE 的会话等待您的 COMMIT。 SELECT...FOR UPDATE请求的锁是独占锁,所以一次只有一个session可以获得锁。因此,如果您的会话持有锁,其他会话将等待。

您不能阻止非锁定读取。另一个会话可以 运行 SELECT 没有锁定子句,并且仍然读取数据。但是他们不能更新数据,也不能请求锁定读取。

您也可以使用 LOCK TABLES 使每个会话请求在 table 上锁定,但您说您想要在行规模上锁定。

您可以使用 GET_LOCK() 功能创建自己的自定义锁。这允许您为每个用户 ID 设置不同的锁。如果对访问 table 的所有代码执行此操作,则不需要使用 FOR UPDATE.

$lockName = 'currency' . (int) $userid;

$_PDO->beginTransaction();

$stmt = $_PDO->prepare("SELECT GET_LOCK(?, -1)");
$stmt->execute([$lockName]);

$stmt = $_PDO->prepare('SELECT * FROM `currency` WHERE `id` = ?');  
$stmt->execute([$userid]);

//maybe do update or not check if

$_PDO->commit();

$stmt = $_PDO->prepare("SELECT RELEASE_LOCK(?)");
$stmt->execute([$lockName]);

这取决于所有合作的客户端代码。他们都需要在处理给定行之前获取锁。您可以使用 SELECT...FOR UPDATE 也可以使用 GET_LOCK().

但是您不能阻止想要使用 SELECT 进行非锁定读取的客户端。