MySQL批量插入事务处理:单条失败不阻断其余数据插入
解决批量插入时单条失败不影响其他数据的问题
嘿,我刚好碰到过类似的场景,给你两个实用的解决方案,能完美解决你这种「单条插入失败不影响其他数据」的需求:
方案1:使用INSERT IGNORE批量插入
MySQL的INSERT IGNORE语句会自动忽略那些违反约束(比如字段长度超限、主键重复)的行,正常插入所有符合要求的数据,完全不用修改应用逻辑,一条SQL就能搞定。
示例代码
把你原来的批量插入语句加上IGNORE关键字即可:
INSERT IGNORE INTO hotels (hotel_id, hotel_name, batch_id) VALUES ('18nt2f4jrqsqipf', 'Hotel Urban Flats Vienna City Center', '2019-02-04_20-35-22'), ('18nt2fajrqsqk4g', 'Hotel Appartements Castello', '2019-02-04_20-35-22'), ('18nt2ghjrqsqx5o', 'Bed and Breakfast Pension Bergkristall', '2019-02-04_20-35-22'), ('18nt2gnjrqsqv48', 'hotel garni corona: einfachheit und gastfreundschaft am comer see - scoene aussich im jeden jahreszeit - gaeste sind immer wilkommen', '2019-02-04_20-35-22'), ('18nt2gnjrqsqw41', 'Hotel Sommerhotel Don Bosco', '2019-02-04_20-35-22');
执行这条语句后,那条hotel_name超长的行会被自动跳过,其他4条数据会正常插入到数据库中。
优缺点
- ✅ 优点:实现简单,性能和普通批量插入一致,适合快速解决问题
- ❌ 缺点:会忽略所有类型的SQL错误,无法直接获取哪些行插入失败,也没法记录失败原因
方案2:应用层逐条插入并捕获异常
如果你需要精确知道哪些行插入失败、失败原因是什么(方便后续排查或重试),可以在应用代码里循环逐条执行INSERT语句,捕获MySQL的异常并跳过错误行。
示例代码(以Python为例)
假设你用的是pymysql库,代码逻辑大概是这样:
import pymysql # 初始化数据库连接(这里需要替换成你的数据库配置) conn = pymysql.connect( host='your_host', user='your_user', password='your_password', database='your_db' ) cursor = conn.cursor() # 你的批量数据 batch_data = [ ('18nt2f4jrqsqipf', 'Hotel Urban Flats Vienna City Center', '2019-02-04_20-35-22'), ('18nt2fajrqsqk4g', 'Hotel Appartements Castello', '2019-02-04_20-35-22'), ('18nt2ghjrqsqx5o', 'Bed and Breakfast Pension Bergkristall', '2019-02-04_20-35-22'), ('18nt2gnjrqsqv48', 'hotel garni corona: einfachheit und gastfreundschaft am comer see - scoene aussich im jeden jahreszeit - gaeste sind immer wilkommen', '2019-02-04_20-35-22'), ('18nt2gnjrqsqw41', 'Hotel Sommerhotel Don Bosco', '2019-02-04_20-35-22'), ] failed_records = [] for record in batch_data: try: # 执行单条插入 cursor.execute( "INSERT INTO hotels (hotel_id, hotel_name, batch_id) VALUES (%s, %s, %s)", record ) conn.commit() except pymysql.MySQLError as e: # 捕获错误,比如错误码1406对应「数据太长」的问题 error_code, error_msg = e.args print(f"插入失败:{record} | 错误码:{error_code} | 原因:{error_msg}") failed_records.append(record) # 回滚当前失败的操作,继续下一条 conn.rollback() # 最后可以把失败的记录保存下来,方便后续处理 if failed_records: print("\n以下记录插入失败:") for rec in failed_records: print(rec) # 关闭连接 cursor.close() conn.close()
优缺点
- ✅ 优点:可以精准捕获每条数据的失败原因,方便后续重试或排查问题
- ❌ 缺点:需要编写更多的应用代码,逐条插入的性能比批量插入稍差,但对于10条的小批量数据来说完全可以忽略
为什么原来的批量插入会全部失败?
默认的INSERT批量语句是原子性的:只要其中一行违反约束(比如字段长度超限),整个语句就会被MySQL回滚,所有行都不会插入。而上面的两种方法,要么让MySQL自动跳过错误行,要么在应用层单独处理每条数据,都能避免这个问题。
内容的提问来源于stack exchange,提问作者Deli Sandor




