所以我有一个表,它有一个唯一的列
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"应该是针对异常的,而不是"规范"。(
还有其他解决方案,但它们更混乱。