2012-05-29 28 views
0

确定这里就是正在发生的基本思想:MySQL的并发和相同的交易麻烦

begin transaction 
some_data=select something from some_table where some_condition; 
if some_data does not exists or some_data is outdated 
    new_data = insert a_new_entry to some_table 
    commit transaction 
    return new_data 
else 
    return some_data 
end 

当多个进程以上同时执行的代码(如客户在同一时刻发出了很多相同的请求),将会插入大量'new_data',而实际上只需要一个'new_data'。

我认为这是一个非常典型的并发情况,但我仍然找不出一个体面的方法来避免它。我可以考虑的事情可能就像让一个工作进程执行select_or_insert作业,或者将隔离级别设置为Serializable(不可接受)。但对我而言,这两者都不令人满意。

PS:该数据库为MySQL,台引擎是InnoDB的,并且隔离级别是可重复读

回答

0

在初始SELECT,用SELECT ... FOR UPDATE

这可以确保记录被锁住,直到事务被提交(或回退)为止,直到事务被提交(或回滚)为止,所以它们在等待SELECT命令并且不会继续到逻辑的其余部分,直到第一个客户已完成其UPDATE

请注意,您需要ROLLBACKelse条件中的事务,否则锁将继续阻塞,直到连接断开。

+0

是的,这部分解决了问题。但是如果some_data不存在呢?如果SELECT ... FOR UPDATE实际上什么都不返回会发生什么? –

+0

@DeanWinchester:好点。另一种方法是使用[named locks](http://dev.mysql.com/doc/en/miscellaneous-functions.html);另一种方法是定义一个适当的'UNIQUE'键,然后试着'INSERT IGNORE',如果失败,则选择旧数据 - 根本不需要交易。 – eggyal

+0

指定的锁似乎是我的案例的完美解决方案。凉! –