MySQL處理重復(fù)數(shù)據(jù)插入的處理方案
1. 引言
在數(shù)據(jù)庫操作中,處理重復(fù)數(shù)據(jù)插入是一個(gè)常見的需求。特別是在批量插入數(shù)據(jù)時(shí),可能會(huì)遇到主鍵沖突或唯一鍵沖突(Duplicate entry)的情況。如何優(yōu)雅地捕獲這類異常并執(zhí)行相應(yīng)的業(yè)務(wù)邏輯,是提高代碼健壯性的關(guān)鍵。
本文將以一個(gè)實(shí)際的Python MySQL數(shù)據(jù)庫操作為例,分析如何優(yōu)化異常處理邏輯,使得當(dāng)出現(xiàn)Duplicate entry錯(cuò)誤時(shí),能夠執(zhí)行特定的業(yè)務(wù)方法(如更新記錄狀態(tài))。同時(shí),我們也會(huì)對(duì)比Java中的類似處理方式,幫助讀者更好地理解不同語言下的異常處理機(jī)制。
2. 問題背景
2.1 原始代碼分析
原始代碼的功能是批量插入手機(jī)號(hào)數(shù)據(jù)到MySQL數(shù)據(jù)庫,其核心邏輯如下:
def insert_into_mysql(phone_numbers, prefix, province, city):
try:
connection = get_db_connection()
cursor = connection.cursor()
data_to_insert = []
for phone_number in phone_numbers:
if len(phone_number) == 11:
suffix = phone_number[-4:]
data_to_insert.append((prefix, suffix, phone_number, province, city))
cursor.executemany(INSERT_QUERY, data_to_insert)
connection.commit()
return True
except Exception as e:
print(f"插入數(shù)據(jù)失敗: {e}")
if connection:
connection.rollback()
return False
finally:
if cursor:
cursor.close()
if connection:
connection.close()
2.2 存在的問題
- 異常處理不夠精細(xì):僅打印錯(cuò)誤信息并回滾,沒有針對(duì)特定錯(cuò)誤(如
Duplicate entry)進(jìn)行特殊處理。 - 業(yè)務(wù)邏輯耦合度低:當(dāng)數(shù)據(jù)重復(fù)時(shí),可能需要執(zhí)行額外操作(如更新記錄狀態(tài)),但原始代碼沒有提供這樣的擴(kuò)展點(diǎn)。
3. 優(yōu)化方案
3.1 目標(biāo)
- 捕獲特定異常:當(dāng)錯(cuò)誤信息包含
Duplicate entry時(shí),執(zhí)行額外邏輯(如調(diào)用update_is_deal方法)。 - 保持代碼健壯性:確保事務(wù)回滾和資源釋放不受影響。
3.2 優(yōu)化后的Python代碼
def insert_into_mysql(phone_numbers, prefix, province, city, url=None):
connection = None
cursor = None
try:
connection = get_db_connection()
if not connection:
print("數(shù)據(jù)庫連接失敗")
return False
cursor = connection.cursor()
data_to_insert = []
for phone_number in phone_numbers:
if len(phone_number) == 11:
suffix = phone_number[-4:]
data_to_insert.append((prefix, suffix, phone_number, province, city))
if not data_to_insert:
print("警告: 沒有有效的手機(jī)號(hào)可插入")
return False
cursor.executemany(INSERT_QUERY, data_to_insert)
connection.commit()
print(f"成功插入 {len(data_to_insert)} 條數(shù)據(jù)")
return True
except Exception as e:
print(f"插入數(shù)據(jù)失敗: {e}")
if connection:
connection.rollback()
# 檢查是否是唯一鍵沖突
if "Duplicate entry" in str(e):
if url: # 確保url有效
update_is_deal(url, province, city) # 執(zhí)行額外邏輯
return False
finally:
if cursor:
cursor.close()
if connection:
connection.close()
3.3 關(guān)鍵優(yōu)化點(diǎn)
- 精細(xì)化異常捕獲:通過檢查異常信息是否包含
"Duplicate entry",判斷是否為唯一鍵沖突。 - 支持額外參數(shù):新增
url參數(shù),確保update_is_deal方法可以正確執(zhí)行。 - 事務(wù)安全:即使執(zhí)行額外邏輯,仍然保證事務(wù)回滾和資源釋放。
4. Java對(duì)比實(shí)現(xiàn)
在Java中,MySQL的Duplicate entry錯(cuò)誤通常對(duì)應(yīng)SQLIntegrityConstraintViolationException,我們可以采用類似的優(yōu)化策略。
4.1 Java版本優(yōu)化代碼
import java.sql.*;
import java.util.List;
public class PhoneNumberDao {
private static final String INSERT_QUERY =
"INSERT INTO phone_numbers (prefix, suffix, phone_number, province, city) " +
"VALUES (?, ?, ?, ?, ?)";
public boolean insertIntoMysql(List<String> phoneNumbers, String prefix,
String province, String city, String url) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DatabaseUtil.getConnection(); // 獲取數(shù)據(jù)庫連接
connection.setAutoCommit(false); // 開啟事務(wù)
statement = connection.prepareStatement(INSERT_QUERY);
for (String phoneNumber : phoneNumbers) {
if (phoneNumber.length() == 11) {
String suffix = phoneNumber.substring(7); // 后4位
statement.setString(1, prefix);
statement.setString(2, suffix);
statement.setString(3, phoneNumber);
statement.setString(4, province);
statement.setString(5, city);
statement.addBatch(); // 加入批處理
}
}
statement.executeBatch(); // 執(zhí)行批處理
connection.commit(); // 提交事務(wù)
return true;
} catch (SQLIntegrityConstraintViolationException e) {
// 捕獲唯一鍵沖突異常
System.err.println("插入數(shù)據(jù)失敗(唯一鍵沖突): " + e.getMessage());
if (connection != null) {
try {
connection.rollback(); // 回滾事務(wù)
} catch (SQLException ex) {
ex.printStackTrace();
}
}
if (url != null) {
updateIsDeal(url, province, city); // 執(zhí)行額外邏輯
}
return false;
} catch (SQLException e) {
System.err.println("插入數(shù)據(jù)失敗: " + e.getMessage());
if (connection != null) {
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
return false;
} finally {
// 關(guān)閉資源
try {
if (statement != null) statement.close();
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private void updateIsDeal(String url, String province, String city) {
// 實(shí)現(xiàn)更新邏輯
System.out.println("檢測到重復(fù)數(shù)據(jù),更新狀態(tài): " + url);
}
}
4.2 Java優(yōu)化點(diǎn)
- 精準(zhǔn)捕獲
SQLIntegrityConstraintViolationException,而不是籠統(tǒng)的SQLException。 - 批處理優(yōu)化:使用
addBatch()和executeBatch()提高插入效率。 - 事務(wù)管理:顯式控制
commit()和rollback(),確保數(shù)據(jù)一致性。
5. 總結(jié)與最佳實(shí)踐
5.1 關(guān)鍵總結(jié)
| 優(yōu)化點(diǎn) | Python 實(shí)現(xiàn) | Java 實(shí)現(xiàn) |
|---|---|---|
| 異常捕獲 | 檢查str(e)是否包含"Duplicate entry" | 捕獲SQLIntegrityConstraintViolationException |
| 事務(wù)管理 | connection.rollback() | connection.rollback() |
| 資源釋放 | finally塊關(guān)閉連接 | finally塊關(guān)閉資源 |
| 批處理優(yōu)化 | cursor.executemany() | addBatch() + executeBatch() |
5.2 最佳實(shí)踐
- 精細(xì)化異常處理:不要僅捕獲
Exception,而應(yīng)根據(jù)業(yè)務(wù)需求區(qū)分不同錯(cuò)誤類型。 - 事務(wù)安全:確保異常發(fā)生時(shí)能正確回滾,避免臟數(shù)據(jù)。
- 資源釋放:使用
try-finally或try-with-resources(Java)確保數(shù)據(jù)庫連接關(guān)閉。 - 日志記錄:在異常處理時(shí)記錄足夠的信息,便于排查問題。
6. 擴(kuò)展思考
- 是否應(yīng)該先查詢?cè)俨迦耄?ul>
- 如果數(shù)據(jù)量較大,先查詢?cè)俨迦肟赡苡绊懶阅埽苯硬东@
Duplicate entry更高效。 - 如何優(yōu)化
update_is_deal邏輯?- 可以引入異步處理(如消息隊(duì)列),避免影響主流程性能。
- 是否可以用
INSERT IGNORE或ON DUPLICATE KEY UPDATE?- 取決于業(yè)務(wù)需求,如果需要靜默忽略重復(fù)數(shù)據(jù),可以使用這些SQL語法。
7. 結(jié)語
通過本文的優(yōu)化案例,我們學(xué)習(xí)了如何在Python和Java中精細(xì)化處理MySQL的Duplicate entry錯(cuò)誤,并執(zhí)行額外的業(yè)務(wù)邏輯。關(guān)鍵在于:
- 精準(zhǔn)捕獲異常
- 確保事務(wù)安全
- 合理優(yōu)化批處理
到此這篇關(guān)于MySQL處理重復(fù)數(shù)據(jù)插入的處理方案的文章就介紹到這了,更多相關(guān)MySQL重復(fù)數(shù)據(jù)插入處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql數(shù)據(jù)庫之主從分離實(shí)例代碼
本篇文章主要介紹了Mysql數(shù)據(jù)庫之主從分離實(shí)例代碼,MySQL數(shù)據(jù)庫設(shè)置讀寫分離,可以使對(duì)數(shù)據(jù)庫的寫操作和讀操作在不同服務(wù)器上執(zhí)行,提高并發(fā)量和相應(yīng)速度。2017-03-03
MYSQL(電話號(hào)碼,身份證)數(shù)據(jù)脫敏的實(shí)現(xiàn)
在日常開發(fā)需求中會(huì)經(jīng)常遇到數(shù)據(jù)脫敏處理,比如身份證號(hào)、手機(jī)號(hào),需要使用*進(jìn)行部分替換顯示。這樣能使敏感隱私信息在一定程度上得到保護(hù)。本文就來介紹一下2021-05-05
Linux系統(tǒng)利用crontab定時(shí)備份Mysql數(shù)據(jù)庫方法
本文教你如果快速利用系統(tǒng)crontab來定時(shí)執(zhí)行備份文件,按日期對(duì)備份結(jié)果進(jìn)行保存2021-09-09
mysqld-nt: Out of memory (Needed 1677720 bytes)解決方法
這篇文章主要介紹了mysqld-nt: Out of memory (Needed 1677720 bytes)解決方法,需要的朋友可以參考下2014-12-12
詳解MySQL中DROP,TRUNCATE 和DELETE的區(qū)別實(shí)現(xiàn)mysql從零開始
注意:這里說的delete是指不帶where子句的delete語句 相同點(diǎn): truncate和不帶where子句的delete, 以及drop都會(huì)刪除表內(nèi)的數(shù)據(jù)2008-04-04

