2012-01-17 53 views
1

我有一种情况,在任何其他事务可以查看给定表之前,特定事务必须更新数据库。具体来说,有一个奖金机制,奖金数量有限,我担心如果两个请求几乎同时到达,第二个请求可能会因第一个请求没有时间而发现奖品仍然可用它需要将其标记为不可用。寻找在mySQL中锁定表的正确方法

我正在查看lock tables的文档,我不清楚发生了什么事情,而且由于测试此功能非常困难(因为它需要同时发送两个请求),所以我希望有一些咨询。

我的需求非常简单。我只需要锁定一张桌子,而其他所有人都可以关注他们的业务。

**request 1**: 
lock prizes; 
select from prizes; 
mark prize as unavailable; 
unlock prizes; 

simultaneous **request n** 
find the prizes table locked and wait for it to unlock //this is not critical, so long as they can just fail gracefully 
select [no prize available] 

正如我所说,这是非常重要的,在这个数据库中的其它表都是由我的锁完全不受影响,我从文档的感觉,当我锁定一个表,选择其他表会产生一个错误,说:“其他表没有被锁定”......我可能没有正确理解这一点,因为这似乎是愚蠢的,但只需确保锁定奖品不会影响其他任何东西。

TIA

回答

1

。这是一个完美的情况下交易。请注意,您的表格需要InnoDB才能正常工作。

start transaction; 
select [your_fields] from [prizes_table] WHERE [your_where] FOR UPDATE; 
// if is a valid recipient and prize gets taken: 
update prizes set available=0 where id=[used_prize_id]; 
commit; 

这应该完全符合你的期望。

+0

真棒!这正是我想要的。 – 2012-01-18 01:49:08

+1

您还应该考虑可用的不同事务隔离并选择适当的事务:http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html – 2012-01-18 11:58:10

1

您应该简单地LOCK prizes WRITE得到你所需要的语义。由于锁定一个或多个表格可以防止您访问任何未锁定锁定期限的表格,因此您还需要锁定 - 读取或写入 - 您需要将所有其他表格作为“标记奖励”不可用“的步骤,如果有的话。

请注意,如果您打算使用别名访问表,则还需要在LOCK语句中提供相同的别名。这个主题在文档中有介绍,但我明确提到它,因为它可能被忽略。

+0

正确...整个数据库被锁定为锁的持续时间的警告是什么使得整个事情变得站不住脚,并且让我觉得我失去了一些明显的东西......我不想锁定整个数据库,并这样做会搞砸各种与这个整体无关的无关进程。另外,我不确定我是否按照你的想法锁定WRITE,因为过程2首先要从奖品中选择(它不能这样做,因为选择不会反映过程1将会写入的信息稍后再执行一秒)。 – 2012-01-18 01:08:54

+0

@ Dr.Dredel:为什么整个数据库?此外,不用说,即使选择,你也会锁定。 – Jon 2012-01-18 01:14:46

0

如果您只需锁定记录,则可以使用select ... for update设置autocommit=0并使用该事务。

这种方式,第一个请求选择该记录和设置锁,则第二请求被阻塞,直到第一请求提交(或回滚)交易或等待超过timout

+0

这看起来比锁的更好的方法,请你详细说明如何实现选择更新?另外,为什么我需要autocommit = 0?我很高兴立即提交更新...或者autocommit = 0是将表放置在表上的机制的一部分? – 2012-01-18 01:11:26

+1

这可能有点过于霸道,因为autocommit = 0将会持续在线程的其余部分,这可能会产生意想不到的后果。明确使用事务更好,所以你不必记得再次设置autocommit = 1(当然,假设这是默认设置)。 – 2012-01-18 01:35:51

+0

实现类似于:'start transaction;请选择,其中用于更新;检查奖品是否可用;设置不可用;提交(或回滚)'。 'autocommit = 0'是需要的,因为如果启用自动提交,则该行不被锁定(通过MySql文档)。无论如何也可以使用交易,而无需设置'autocommit = 0' – Gianluca 2012-01-18 08:26:38