我現(xiàn)在遇到了一個(gè)問題,就是在使用MySQL數(shù)據(jù)庫(kù),和TP5框架的時(shí)候,先查詢數(shù)據(jù)庫(kù)是否存在某條數(shù)據(jù),如果不存在就寫入。但是在高并發(fā)的情況下,會(huì)出現(xiàn)同一條數(shù)據(jù)被多次寫入的情況。這應(yīng)該怎么解決呢?
首先,為什么會(huì)發(fā)生這種情況呢?假設(shè)有兩個(gè)并發(fā)的請(qǐng)求同時(shí)到達(dá)服務(wù)器,他們都會(huì)先去查詢數(shù)據(jù)庫(kù)是否存在這條數(shù)據(jù)。由于這兩個(gè)請(qǐng)求幾乎是同時(shí)進(jìn)行的,所以在查詢的時(shí)候,可能都發(fā)現(xiàn)數(shù)據(jù)庫(kù)中沒有這條記錄,于是都執(zhí)行了插入操作,導(dǎo)致重復(fù)數(shù)據(jù)。這就是典型的并發(fā)問題,因?yàn)椴樵兒筒迦脒@兩個(gè)操作不是原子性的,中間存在時(shí)間差,導(dǎo)致多個(gè)請(qǐng)求同時(shí)判斷不存在,然后都插入。
那怎么解決呢?傳統(tǒng)的做法可能是加唯一索引。比如,如果數(shù)據(jù)中的某個(gè)字段或者多個(gè)字段的組合是唯一的,那就在數(shù)據(jù)庫(kù)里給這些字段加上唯一索引。這樣即使兩個(gè)請(qǐng)求同時(shí)插入,數(shù)據(jù)庫(kù)會(huì)阻止后面的插入,拋出唯一鍵沖突的錯(cuò)誤。這時(shí)候,程序里捕獲這個(gè)錯(cuò)誤,然后進(jìn)行相應(yīng)的處理,比如忽略或者提示重復(fù)。這種方法應(yīng)該有效,但需要確定哪些字段可以作為唯一標(biāo)識(shí),并且這些字段的值在插入時(shí)確實(shí)是唯一的。
INSERT IGNORE
是 MySQL 提供的一種語法擴(kuò)展,其核心作用是 在插入數(shù)據(jù)時(shí)忽略因唯一鍵沖突或數(shù)據(jù)類型錯(cuò)誤等導(dǎo)致的錯(cuò)誤,避免因插入失敗而中斷操作。在高并發(fā)場(chǎng)景下,它可以用來靜默處理重復(fù)數(shù)據(jù)的插入問題,但需要結(jié)合 唯一索引 才能生效。
INSERT IGNORE 的注意事項(xiàng)
1、必須依賴唯一索引
如果沒有唯一索引,INSERT IGNORE 無法識(shí)別重復(fù)數(shù)據(jù),會(huì)正常插入所有記錄。
2、靜默忽略錯(cuò)誤
除了唯一鍵沖突,INSERT IGNORE 還會(huì)忽略以下錯(cuò)誤:
數(shù)據(jù)類型轉(zhuǎn)換錯(cuò)誤(如將字符串插入整數(shù)字段)。
違反 NOT NULL 約束時(shí)插入默認(rèn)值。
需謹(jǐn)慎使用,避免掩蓋其他潛在問題。
3、自增 ID 的遞增
即使插入被忽略,表的自增 ID(AUTO_INCREMENT)仍會(huì)遞增。例如:
當(dāng)前最大 ID 是 100。
執(zhí)行一次 INSERT IGNORE 失敗后,下一次成功插入的 ID 會(huì)是 102(中間跳過了 101)。
4、性能優(yōu)勢(shì)
相比先查詢?cè)俨迦耄⊿ELECT + INSERT),INSERT IGNORE 在數(shù)據(jù)庫(kù)層面保證原子性,避免并發(fā)時(shí)的重復(fù)插入問題。