繁体   English   中英

安全地减少用户余额列。 我应该使用乐观锁吗?

[英]Safely decrease User balance column. Should I use optimistic locking?

我有一个简单的Silex Web应用程序与MySQL / Doctrine ORM。 每个用户都有balance (这是一个简单的应用程序,所以只有列是好的)我需要在一些操作后减少它(当然检查它是> 0)。

据我所知,我可以使用乐观锁定来避免冲突/漏洞。 我已阅读文档http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html但我找不到任何关于使用它的完整示例。

我在哪里可以获得“预期版本”? 我是否需要将其作为输入传递(隐藏表单字段)? 还是有更好的方法? 文档说了一些关于会话的内容,但我不知道如何将它存储在那里(每个请求都更新会话?)。

另外,如果我将它作为输入传递,那么据我所知,在捕获OptimisticLockException无法自动重复查询而不通知用户这一点? (例如,如果用户打开两个选项卡并逐个提交请求)

我的目标是在用户同时发送多个请求并且平衡仅减少一次等时防止潜在问题。因此,如果能够在不涉及用户的情况下自动重复锁定错误,那将是一件好事。 因为如果我通过表单传递它,那么很可能因为多个选项卡而出现此错误。 所以看起来有点复杂,也许有其他东西而不是乐观锁定?

在“user”表中创建一个名为“version”的列,并将其设置为“timestamp”列(使用“on update CURRENT_TIMESTAMP”属性)。 所以,“用户”ORM类将如下所示:

class User
{
    // ...
    /** @Version @Column(type="timestamp") */
    private $version;
    // ...
}

现在,用“版本”读取当前记录。

$theEntityId = YOUR ENTITY ID;
$entity = $em->find('User', $theEntityId);
$expectedVersion = entity->version;
try {
   // assert version
    $em->lock($entity, LockMode::OPTIMISTIC, $expectedVersion);

    // do the work

    $em->flush();
} 
catch(OptimisticLockException $e) {
    echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
}

您应该仅对无法以原子方式执行的操作使用锁定。 因此,如果可能,请避免查询对象,检查金额,然后更新它。 相反,如果您这样做:

update user set balance = (balance + :amount) 
where (balance + :amount) >= 0 
and id = :user_id

您将在一次操作中检查和更新,如果检查通过并且余额已更新,则更新的行数将为1,否则为0。

乐观锁将允许并发访问读取实体(意味着可能有一些线程将读取过期数据),而悲观锁将锁定读取,如果有人正在该注册表上执行操作。

取决于您希望并发访问的准确性如何?! 读取过时的数据是否可以?

例如:

{OTIMISTIC LOCK}
Thread1 -> read(balance1[200$][version=1])
Thread2 -> read(balance1[200$][version=1])
Thread1 -> balance.add(100$).save()[300$ total and version=2]
Thread2 -> balance.add(50$).save()[OtimisticLockError Version-> 2 != 1]

{PESSIMISTIC LOCK}
Thread1 -> read(balance1[200$]) [lock for update | select for update |... depends on DB])
Thread2 -> read(balance1) [Pessimistic lock exception]
Thread1 -> balance.add(100$).save()[300$ total]
Thread1 -> release lock balance1
Thread2 -> read(balance1[300$]) Ok

OPTIMISTIC LOCK

悲伤锁定

PESSIMISTIC与OPTIMISTIC

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM