在数据库操作中,处理重复数据插入是一个常见的需求。特别是在批量插入数据时,可能会遇到主键冲突或唯一键冲突(Duplicate entry)的情况。如何优雅地捕获这类异常并执行相应的业务逻辑,是提高代码健壮性的关键。
本文将以一个实际的Python MySQL数据库操作为例,分析如何优化异常处理逻辑,使得当出现Duplicate entry错误时,能够执行特定的业务方法(如更新记录状态)。同时,我们也会对比Java中的类似处理方式,帮助读者更好地理解不同语言下的异常处理机制。
原始代码的功能是批量插入手机号数据到MySQL数据库,其核心逻辑如下:
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"插入数据失败: {e}")
if connection:
connection.rollback()
return False
finally:
if cursor:
cursor.close()
if connection:
connection.close()Duplicate entry)进行特殊处理。Duplicate entry时,执行额外逻辑(如调用update_is_deal方法)。def insert_into_mysql(phone_numbers, prefix, province, city, url=None):
connection = None
cursor = None
try:
connection = get_db_connection()
if not connection:
print("数据库连接失败")
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("警告: 没有有效的手机号可插入")
return False
cursor.executemany(INSERT_QUERY, data_to_insert)
connection.commit()
print(f"成功插入 {len(data_to_insert)} 条数据")
return True
except Exception as e:
print(f"插入数据失败: {e}")
if connection:
connection.rollback()
# 检查是否是唯一键冲突
if "Duplicate entry" in str(e):
if url: # 确保url有效
update_is_deal(url, province, city) # 执行额外逻辑
return False
finally:
if cursor:
cursor.close()
if connection:
connection.close()"Duplicate entry",判断是否为唯一键冲突。url参数,确保update_is_deal方法可以正确执行。在Java中,MySQL的Duplicate entry错误通常对应SQLIntegrityConstraintViolationException,我们可以采用类似的优化策略。
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(); // 获取数据库连接
connection.setAutoCommit(false); // 开启事务
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(); // 执行批处理
connection.commit(); // 提交事务
return true;
} catch (SQLIntegrityConstraintViolationException e) {
// 捕获唯一键冲突异常
System.err.println("插入数据失败(唯一键冲突): " + e.getMessage());
if (connection != null) {
try {
connection.rollback(); // 回滚事务
} catch (SQLException ex) {
ex.printStackTrace();
}
}
if (url != null) {
updateIsDeal(url, province, city); // 执行额外逻辑
}
return false;
} catch (SQLException e) {
System.err.println("插入数据失败: " + e.getMessage());
if (connection != null) {
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
return false;
} finally {
// 关闭资源
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) {
// 实现更新逻辑
System.out.println("检测到重复数据,更新状态: " + url);
}
}SQLIntegrityConstraintViolationException,而不是笼统的SQLException。addBatch()和executeBatch()提高插入效率。commit()和rollback(),确保数据一致性。优化点 | Python 实现 | Java 实现 |
|---|---|---|
异常捕获 | 检查str(e)是否包含"Duplicate entry" | 捕获SQLIntegrityConstraintViolationException |
事务管理 | connection.rollback() | connection.rollback() |
资源释放 | finally块关闭连接 | finally块关闭资源 |
批处理优化 | cursor.executemany() | addBatch() + executeBatch() |
Exception,而应根据业务需求区分不同错误类型。try-finally或try-with-resources(Java)确保数据库连接关闭。Duplicate entry更高效。update_is_deal逻辑? INSERT IGNORE或ON DUPLICATE KEY UPDATE? 通过本文的优化案例,我们学习了如何在Python和Java中精细化处理MySQL的Duplicate entry错误,并执行额外的业务逻辑。关键在于:
希望这篇博客能帮助你在实际开发中更好地处理数据库冲突问题! 🚀