在具有唯一列的数据库中插入时,可以使用try/catch而不是检查重复项吗



所以我有一个表,它有一个唯一的列

transactions : id , trace_code (unique) , amount , created_at 

我有一个机器人,它从银行api读取我的事务,并使用cronjob每隔x分钟将它们插入我的数据库。。。所以每次执行都有很多重复的值

这样,在将数据插入该表之前,我可以检查重复项但只插入try/catch块要容易得多。。。这意味着更少的代码和更少的查询

try {
$tr = new Transaction();
$tr->amount = 1000 ;
$tr->trace_code = 123 ; 
$tr->save();
}
catch(Exception $e){
echo " duplicate value";
}

所以我的问题是,当我知道会有很多重复的值时,以这种方式插入有什么缺点吗?

是的,这是正确的方法。否则,在您检查行是否存在之后,但在您设法进行插入之前,其他请求可能会插入行。(在您的cron作业的两个实例恰好同时运行的情况下(。

但请验证您得到的异常是否真的来自一个唯一的索引异常,而不是其他失败的异常,这样您就不会忽略其他错误。

您可能对Eloquent的firstOrNew方法感兴趣。如果找不到匹配的记录,它将创建一个新的模型实例,而不立即保存。然后,您可以相应地决定保存/更新:

// $tr will be the first matching record or a new instance
$tr = Transaction::firstOrNew([
'amount' => 1000,
'trace_code' => 123
]);
// do stuff....
$tr->save();

使用锁来防止其他查询更新行。

我认为其他答案中存在一个潜在的问题——焚烧id。

假设您的表包含

id INT AUTO_INCREMENT PRIMARY KEY,
trace_code ... UNIQUE

然后。。。当您尝试插入一个重复的行(因为trace_code(并且它陷阱(或是IGNOREd(时,id已经被碰撞。

看看SELECT MAX(id) FROM tbl,看看是否发生了这种情况。

在某个时刻,INT将溢出;这会引起麻烦。

我喜欢的解决方案是去掉id,使trace_code成为PRIMARY KEY。然后INSERT IGNORE要么插入,要么什么都不做。不需要额外的检查、诱捕等。(继续尝试..catch——以防出现其他错误。"catch"应该是针对异常的,而不是"规范"。(

还有其他解决方案,但它们更混乱。

相关内容

  • 没有找到相关文章