报错Could not execute JDBC batch update和java.sql.BatchUpdateException: Duplicate e

本文介绍了一个关于使用Hibernate框架时遇到的批量更新异常问题及解决方案。作者通过调整配置文件中的唯一性设置解决了CouldnotexecuteJDBCbatchupdate和java.sql.BatchUpdateException错误。
报错Could not execute JDBC batch update和java.sql.BatchUpdateException: Duplicate e
最近学hibernate,写了一段代码,第一次执行没问题,第二次执行报错了,想了一下,不应该是其他毛病,且报错是更新(update)出错,估计是第二次执行的时候刚好与第一次执行的结果出现了矛盾,于是去数据库将第一次执行的结果(主码)改了一下,再执行就不会报错了,呵呵(主要原因还是我在配置文件中对Department类和Employee类的id设置了唯一性)
package cn.itcast.hibernate;

import org.hibernate.Session;
import org.hibernate.Transaction;

import cn.itcast.hibernate.HibernateUtils;

import cn.itcast.hibernate.domain.Department;
import cn.itcast.hibernate.domain.Employee;

public class Many2One {

public static void main(String[] args){
add();
}


static Department add(){
Session s = null ;
Transaction tx = null;
try{
Department depart = new Department();
depart.setName("depart name");

Employee emp = new Employee();
emp.setDepart(depart);//因为这一行代码,将Employee和Department关联起来了
emp.setName("emp name");
s = HibernateUtils.getSession();
tx = s.beginTransaction();
s.save(depart);//先保存了depart
s.save(emp);//后保存emp,从而保证了emp中的Department不是空的
tx.commit();
return depart;
}finally{
if(s != null)
s.close();
}

}

}
### 问题分析与解决方案 在批量插入数据时,如果出现 `java.sql.BatchUpdateException: Duplicate entry for key PRIMARY` 错误,说明数据库中已经存在具有相同主键值的记录。此问题的根本原因通常是由于违反了数据库表的唯一性约束(如主键或唯一索引)。以下是解决该问题的详细方法[^1]。 #### 1. 数据预检查 在执行批量插入之前,可以对即将插入的数据进行预检查,确保没有重复的主键或唯一索引字段。例如,在 MyBatis 中可以通过查询数据库来验证数据是否存在: ```java List<Record> recordsToInsert = new ArrayList<>(); for (Record record : batchRecords) { if (!isRecordExists(record.getPrimaryKey())) { recordsToInsert.add(record); } } insertBatch(recordsToInsert); private boolean isRecordExists(Object primaryKey) { // 查询数据库以判断主键是否已存在 return sqlSession.selectOne("selectRecordByPrimarykey", primaryKey) != null; } ``` 通过上述代码,可以在插入前过滤掉重复的数据[^2]。 #### 2. 使用 ON DUPLICATE KEY UPDATE 如果使用的是 MySQL 数据库,可以通过 SQL 的 `ON DUPLICATE KEY UPDATE` 语法来处理冲突。MyBatis 支持动态 SQL,因此可以在 Mapper 文件中定义如下语句: ```xml <insert id="insertOrUpdateBatch" parameterType="java.util.List"> INSERT INTO your_table (id, column1, column2) VALUES <foreach collection="list" item="item" separator=","> (#{item.id}, #{item.column1}, #{item.column2}) </foreach> ON DUPLICATE KEY UPDATE column1 = VALUES(column1), column2 = VALUES(column2); </insert> ``` 上述语句会在插入数据时检测到主键冲突时更新指定字段[^3]。 #### 3. 批量插入时捕获异常并处理 如果无法在插入前检查数据,也可以通过捕获 `BatchUpdateException` 并处理冲突的记录。以下是一个示例代码: ```java try { sqlSession.insert("insertBatch", batchRecords); } catch (BatchUpdateException e) { List<Integer> updateCounts = Arrays.stream(e.getUpdateCounts()) .boxed() .collect(Collectors.toList()); handleBatchUpdateException(batchRecords, updateCounts, e); } private void handleBatchUpdateException(List<Record> batchRecords, List<Integer> updateCounts, BatchUpdateException e) { for (int i = 0; i < updateCounts.size(); i++) { if (updateCounts.get(i) == Statement.EXECUTE_FAILED) { Record failedRecord = batchRecords.get(i); log.error("Failed to insert record: {}", failedRecord, e); // 可以选择忽略错误、更新现有记录或通知前端 } } } ``` 通过上述方式,可以逐条处理失败的记录,并根据业务需求决定如何处理冲突[^4]。 #### 4. 调整数据库设计 如果频繁出现主键冲突问题,可能需要重新评估数据库的设计。例如: - 如果主键是自增字段,确保客户端生成的主键值不会与数据库中的值冲突。 - 如果主键是 UUID 或其他全局唯一标识符,可以考虑使用更复杂的生成策略(如 Snowflake 算法)[^5]。 --- ### 示例代码 以下是一个完整的 MyBatis 批量插入示例,结合了预检查异常处理: ```java public void insertBatchWithCheck(List<Record> batchRecords) { List<Record> filteredRecords = new ArrayList<>(); for (Record record : batchRecords) { if (!isRecordExists(record.getPrimaryKey())) { filteredRecords.add(record); } } try { sqlSession.insert("insertBatch", filteredRecords); } catch (BatchUpdateException e) { List<Integer> updateCounts = Arrays.stream(e.getUpdateCounts()) .boxed() .collect(Collectors.toList()); handleBatchUpdateException(filteredRecords, updateCounts, e); } } private boolean isRecordExists(Object primaryKey) { return sqlSession.selectOne("selectRecordByPrimarykey", primaryKey) != null; } private void handleBatchUpdateException(List<Record> batchRecords, List<Integer> updateCounts, BatchUpdateException e) { for (int i = 0; i < updateCounts.size(); i++) { if (updateCounts.get(i) == Statement.EXECUTE_FAILED) { Record failedRecord = batchRecords.get(i); log.error("Failed to insert record: {}", failedRecord, e); } } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值