使用Java Servlet更新数据库记录时排查重复项问题
解决更新数据库记录时重复项检查误判的问题
我一眼就看出问题所在了:你的重复检查逻辑isFilePositionExist在更新时没有排除当前正在修改的那条记录!不管你改不改File_Position,它都会把当前行的这个值算进去,所以自然会提示重复。下面给你一步步解决:
1. 改造重复检查方法,排除当前记录
首先,我们需要给isFilePositionExist方法增加参数,传入当前要更新记录的唯一标识(从你的UPDATE语句来看,Match_Type_Id+Field_Label+Version是用来定位更新行的,所以用这三个作为排除条件)。同时把原来的Statement改成PreparedStatement,避免SQL注入风险:
public boolean isFilePositionExist(int filePosition, String matchTypeId, String excludeFieldLabel, int excludeVersion) throws SQLException { boolean isExist = false; Connection conn = null; PreparedStatement pst = null; ResultSet rs = null; try { conn = DataSource.getDBConnection(); // 基础查询条件:匹配File_Position和Match_Type_Id String sql = "SELECT COUNT(File_Position) AS Count FROM FIELD_MAPPING WHERE File_Position = ? AND Match_Type_Id = ?"; // 如果是更新场景,加入排除当前记录的条件 if (excludeFieldLabel != null && excludeVersion != -1) { sql += " AND NOT (Match_Type_Id = ? AND Field_Label = ? AND Version = ?)"; } pst = conn.prepareStatement(sql); // 设置基础参数 pst.setInt(1, filePosition); pst.setString(2, matchTypeId); // 如果有排除参数,继续设置 if (excludeFieldLabel != null && excludeVersion != -1) { pst.setString(3, matchTypeId); pst.setString(4, excludeFieldLabel); pst.setInt(5, excludeVersion); } rs = pst.executeQuery(); if (rs.next() && rs.getInt("Count") > 0) { isExist = true; } } catch (SQLException e) { e.printStackTrace(); throw e; } finally { DataSource.close(pst); DataSource.close(rs); DataSource.close(conn); } return isExist; } // 为插入场景重载一个方法,不需要排除任何记录 public boolean isFilePositionExist(int filePosition, String matchTypeId) throws SQLException { return isFilePositionExist(filePosition, matchTypeId, null, -1); }
2. 更新前调用检查方法时传入排除参数
在更新逻辑里,调用检查方法时,把你用来定位更新行的previousFieldLabel和previousVersion传进去,这样就会跳过当前行的检查:
// 更新前的重复检查逻辑 if(fieldMappingDAO.isFilePositionExist(fieldsMapping.getFilePosition(), fieldsMapping.getMatchTypeId(), previousFieldLabel, previousVersion)) { sb.append("File Position Already Exists."); isError = true; }
3. 修正UPDATE语句的语法错误
另外,你的editMapping方法里的SQL语句有明显错误:File_Position = Display_Order = ?这部分写串了,应该是两个独立的赋值。同时参数索引也要对应调整,否则会导致SQL执行失败:
public void editMapping(fieldsMapping fieldsMapping, int previousVersion, String previousFieldLabel) throws SQLException { Connection conn = null; PreparedStatement pst = null; try { conn = DataSource.getDBConnection(); // 修正语法错误,拆分File_Position和Display_Order的赋值 String sql = "UPDATE FIELD_MAPPING SET Field_Label = ?, Version = ?, Index_Field_Name = ?, Stage_Field_Name = ?, " + "File_Position = ?, Display_Order = ?, Min_Template_Version = ?, Last_Update_Date = ? " + "WHERE Match_Type_Id = ? AND Field_Label = ? AND Version = ?"; pst = conn.prepareStatement(sql); // 按SQL顺序设置参数 pst.setString(1, fieldsMapping.getFieldLabel()); pst.setInt(2, fieldsMapping.getVersion()); pst.setString(3, fieldsMapping.getIndexFieldName()); pst.setString(4, fieldsMapping.getStageFieldName()); pst.setInt(5, fieldsMapping.getFilePosition()); pst.setInt(6, fieldsMapping.getDisplayOrder()); pst.setString(7, fieldsMapping.getMinTemplateVersi()); pst.setTimestamp(8, new Timestamp(System.currentTimeMillis())); // WHERE子句的参数 pst.setString(9, fieldsMapping.getMatchTypeId()); pst.setString(10, previousFieldLabel); pst.setInt(11, previousVersion); int a = pst.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); throw e; } finally { DataSource.close(pst); DataSource.close(conn); } }
这样改造后,更新时就只会检查其他行的重复项,不会把当前行算进去了。插入时调用重载的方法,依然保持原来的正确逻辑。
内容的提问来源于stack exchange,提问作者user2410266
相关产品推荐
相关产品推荐

