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

is it ok to use try/catch instead of checking for duplicate when inserting in db with unique column?

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

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

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

所以我可以在插入数据之前检查重复项 table 但是插入 try/catch 块要容易得多……这意味着更少的代码和更少的查询

try {

 $tr = new Transaction();
 $tr->amount = 1000 ;
 $tr->trace_code = 123 ; 
 $tr->save();
}
catch(\Exception $e){

  echo " duplicate value";
}

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

是的,这是正确的方法。否则,其他请求可能会在您检查它是否存在之后但在您设法执行插入之前插入一行。 (以防您的 cron 作业的 2 个实例恰好同时 运行)。

但请确认您得到的异常确实来自唯一索引异常,而不是其他失败的异常,因此您不会最终忽略其他错误。

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

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

// do stuff....
$tr->save();

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

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

假设您的table包含

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 插入或静默不做任何事情。不需要额外的检查、诱捕等。 (继续执行 try..catch —— 以防 其他东西 出错。"Catch" 应该用于异常,而不是 "norm"。)

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