拍卖出价 - SELECT LOCK IN SHARE MODE 会保留最新信息吗?
Posted
技术标签:
【中文标题】拍卖出价 - SELECT LOCK IN SHARE MODE 会保留最新信息吗?【英文标题】:Auction Bid - Will SELECT LOCK IN SHARE MODE keep information at its most recent? 【发布时间】:2012-01-26 16:31:42 【问题描述】:我目前正在研究如何在我的拍卖网站项目中管理大量出价。由于很可能有些人可能会在同一时间发送投标,因此很明显我需要确保有锁以防止任何数据损坏。
我已经开始使用SELECT LOCK IN SHARE MODE
,它声明If any of these rows were changed by another transaction that has not yet committed, your query waits until that transaction ends and then uses the latest values.
http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
这向我表明,投标将进入一个队列,在该队列中处理和检查每个投标,以确保投标高于当前投标,如果在此队列中插入插入后发生变化,则最新投标金额被使用。
但是,我了解到,如果两个用户尝试同时出价并且没有查询可以保持锁定,则可能会出现破坏性死锁问题。因此我也考虑过使用SELECT FOR UPDATE
,但这也会禁用我不太确定的任何读取。
如果有人能对这个问题有所了解,将不胜感激,如果您能推荐任何其他数据库,如 NoSQL 更合适,那将非常有帮助!!!
编辑:这本质上是一个并发问题,我不想使用不正确/旧数据检查当前出价,因此会在某些出价上产生“丢失更新”。
【问题讨论】:
【参考方案1】:就其本身而言,两个同时更新不会导致死锁,只是暂时阻塞。我们称他们为 Bid A
和 Bid B
。
虽然我们同时考虑它们,但首先要获取锁。我们会说A
到达那里的速度快了 1 毫秒。
A
在有问题的行上获得锁。 B
的锁请求进入队列,必须等待属于A
的锁被释放。一旦锁定A
被释放,B
就会获得它的锁定。
您的代码可能还有更多内容,但从您的问题来看,正如我所描述的那样,没有死锁场景。为了死锁,A
必须等待B
释放它对另一个资源的锁定,但B
不会释放它的锁定,直到它获得A
的资源上的锁定。
如果您需要实时验证出价,您可以:
A.使用适当的事务隔离级别(可能是可重复读取,这是 InnoDB 中的默认设置)并在显式事务中执行您的选择和更新。
BEGIN TRAN
SELECT ... FOR UPDATE
IF ...
UPDATE ...
COMMIT
B.在 Update 语句本身中执行检查逻辑。换句话说,构造您的 UPDATE 查询,使其仅在当前出价低于新出价时影响行。如果没有记录受到影响,则出价太低。这是一种可能的方法,可以减少对数据库的工作,但有其自身的考虑。
UPDATE ...
WHERE currentBid < newBid
我个人的投票是选择 A,因为我不知道您的逻辑有多复杂。
repeatable read
隔离级别将确保每次在事务中读取给定记录时,值都保证是相同的。它通过在行上保持锁定来防止其他人更新给定行,直到您的事务提交或回滚。在最后一个连接完成其事务之前,一个连接无法更新您的表。
底线是您的选择/更新将在您的数据库中是原子的,因此您不必担心丢失更新。
关于并发性,关键是让您的事务尽可能短。进来,出去。默认情况下,您无法读取正在更新的记录,因为它处于不确定状态。这些更新和读取应该只需要几分之一秒。
【讨论】:
对于像这样的应用程序,您需要serializable
,至少对于实际的“检查状态,出价”部分。
@M_M 谢谢!正是我需要的。只是需要澄清一下!
很好地阅读 InnoDB 中的隔离级别 ovaistariq.net/597/…
@DanielWest,请参阅此问题的答案以获得对差异的良好解释:***.com/questions/4034976/…。
默认repeatable read
下的SELECT ... FOR UPDATE
将为您提供与SERIALIZABLE
事务相同的好处。以上是关于拍卖出价 - SELECT LOCK IN SHARE MODE 会保留最新信息吗?的主要内容,如果未能解决你的问题,请参考以下文章
来自 SQL 的 Laravel Eloquent ORM 聚合函数
万维网源代码正在被发明人拍卖,有人出价1800万,还在不断上涨
微信小程序拍卖商品详情页设计与交互实现(包含倒计时实时更新出价)