在 MySQL 中,我必须检查 select 查询是否返回任何记录,如果没有,我插入一条记录。但我担心 PHP 脚本中的整个 if-else 操作并不像我希望的那样原子,即在某些情况下会中断,例如,如果在需要处理相同记录的情况下调用脚本的另一个实例:
if(select returns at least one record)
{
update record;
}
else
{
insert record;
}
我在这里没有使用事务,并且自动提交已打开。我正在使用 MySQL 5.1 和 PHP 5.3。该表是InnoDB。我想知道上面的代码是否不是最优的并且确实会崩溃。我的意思是两个实例重新输入相同的脚本,并且发生以下查询序列:
- 实例1尝试选择记录,没有找到记录,进入插入查询 block
- 实例2尝试选择记录,没有找到记录,进入插入查询 block
- 实例 1 尝试插入记录,成功
- 实例 2 尝试插入记录,失败,自动中止脚本
这意味着实例 2 将中止并返回错误,跳过插入查询语句后面的任何内容。我可以使错误不是致命的,但我不喜欢忽略错误,我更想知道我的恐惧是否真实存在。
更新:我最终做了什么(这样可以吗?)
相关表有助于限制(实际上是允许/拒绝)应用程序发送给每个收件人的消息数量。系统不应在 Z 时段内向接收者 Y 发送多于 X 条消息。该表[概念上]如下:
create table throttle
(
recipient_id integer unsigned unique not null,
send_count integer unsigned not null default 1,
period_ts timestamp default current_timestamp,
primary key (recipient_id)
) engine=InnoDB;
[有点简化/概念性的] PHP 代码块应该执行原子事务,维护表中的正确数据,并根据限制状态允许/拒绝发送消息:
function send_message_throttled($recipient_id) /// The 'Y' variable
{
query('begin');
query("select send_count, unix_timestamp(period_ts) from throttle where recipient_id = $recipient_id for update");
$r = query_result_row();
if($r)
{
if(time() >= $r[1] + 60 * 60 * 24) /// The numeric offset is the length of the period, the 'Z' variable
{/// new period
query("update throttle set send_count = 1, period_ts = current_timestamp where recipient_id = $recipient_id");
}
else
{
if($r[0] < 5) /// Amount of messages allowed per period, the 'X' variable
{
query("update throttle set send_count = send_count + 1 where recipient_id = $recipient_id");
}
else
{
trigger_error('Will not send message, throttled down.', E_USER_WARNING);
query('rollback');
return 1;
}
}
}
else
{
query("insert into throttle(recipient_id) values($recipient_id)");
}
if(failed(send_message($recipient_id)))
{
query('rollback');
return 2;
}
query('commit');
}
好吧,忽略 InnoDB 死锁发生的事实,这很好不是吗?我并不是在拍胸脯或做任何事情,但这只是我能做的性能/稳定性的最佳组合,缺少使用 MyISAM 并锁定整个表,我不想这样做,因为与更新/插入相比,我不想这样做选择。
最佳答案
看来您已经知道问题的答案以及如何解决您的问题。这是一个真实的问题,您可以使用以下方法之一来解决它:
- 选择...进行更新
- 插入...重复 key 更新
- 交易(不要使用 MyIsam)
- 表锁
关于php - MySQL 和 PHP : Atomicity and re-entrancy of a PHP code block executing two subsequent queries - how dangerous?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3104365/