【问题标题】:SQLIntegrityConstraintViolationException Due to Duplicate Key ValueSQLIntegrityConstraintViolationException 由于重复键值
【发布时间】:2015-12-01 17:06:43
【问题描述】:

我在尝试使用以下代码将新闻行插入数据库表时遇到完整性约束违规错误。

public void ExtractBoard() throws IOException, SQLException {
    int rows = 0;
    String sqlInser = "INSERT INTO APP.SUBSCRIBERBR (subID, boardno)"+"VALUES (?,?)";
    PreparedStatement  stmt = conn.prepareStatement(sqlInser, Statement.RETURN_GENERATED_KEYS);
    String[] AryFiles2 = rf.OpenFile();
    int i,j;
    String p1 = "", p2 = "";
    for (i=0; i<AryFiles2.length; i++) {
        if (AryFiles2[i].contains("ADD VSBR")) {
            String[][] parts = this.LineParts();
            Scanner in = new Scanner(parts[i][0]).useDelimiter("[^0-9]+");
            int intst = in.nextInt();
            p1 = String.valueOf(intst);
            for (j=0; j<parts[1].length; j++) {
               if (parts[i][j].contains("MN")) {
                   Scanner inn = new Scanner(parts[i][j]).useDelimiter("[^0-9]+");
                   int intstr = inn.nextInt();
                   p2 = String.valueOf(intstr); 

               }
           }
       }
       if(p1 != null && p2 != null){
           stmt.setString(1, p1);
           stmt.setString(2,p2);
           rows = stmt.executeUpdate();
       }
       else {
           throw new SQLException("Null parameters");
       }
   }
}

这是我收到的错误消息。

java.sql.SQLIntegrityConstraintViolationException:该语句被中止,因为它会导致在“SUBSCRIBERBR”上定义的“SQL150827011836400”标识的唯一或主键约束或唯一索引中出现重复键值。

我该如何解决这个问题?

【问题讨论】:

  • 如果您可以发布数据库表的方案会有点帮助。但是异常本身已经告诉您,您尝试将一个值作为已经存在的主键(或至少插入到唯一列)中插入数据库。因此,您还应该检查从中读取值的文件的内容。

标签: java sql jdbc


【解决方案1】:

您的 subID 变量似乎重复了。 (您的表中有另一条具有相同 subID 的记录)

可能的原因有:

  1. 你的文件读取方法有问题,你最终读错了输入文件。

  2. 您的输入文件已经包含重复的键。

  3. 一切正常,但您试图在没有先清理它的情况下针对同一个数据库运行代码,因此您最终会在之前的运行中找到具有此子 ID 的记录。

【讨论】:

  • 我认为该文件有重复的键。我想获得一些关于如何添加代码行以跳过已经插入的键的帮助,使用 sql 关键字 'EXISTS' 或其他东西。
  • 首先你应该验证你的假设。 然后作为一种可能的解决方案(因为您的目标是简单的)我建议简单地捕获 SQLIntegrityConstraintViolationException 并跳过有问题的行。
  • 如果密钥已经写入,询问数据库更容易(并且比异常处理更便宜)。您可以使用简单的选择,例如select subID from APP.SUBSCRIBERBR where subID = ?。如果没有行,则可以插入。
【解决方案2】:

您永远不会将p1p2 设置为null,因此如果if 语句在第一次迭代中为假,则插入"", "",如果if 语句在后续迭代中为假,则您插入与上一次迭代相同的 值。

【讨论】:

  • 如果他插入值 "", "" 他应该得到一个非空约束违规或类型违规,因为subID 是类型 number/int 的主键,我猜。
  • @dev.null 你是对的,但是该代码有很多,so 有很多问题,我什至无法解决假设问题关于未显示的内容,例如列的数据类型,直到列表的最下方。相反,我选择专注于保证重复错误的逻辑部分,这就是问题所在,而无需明确了解传入数据。 --- 让我们看看.... 是的,可能有一行或两行我没有问题的代码。如果您计算带端括号的行数,则更多。
【解决方案3】:

我认为您读取了错误的 int,因此您最终得到了错误的值并生成了重复的键,这违反了约束。

您的主键来自parts[i][0]i 从 0 开始)在以下行:

Scanner in = new Scanner(parts[i][0]).useDelimiter("[^0-9]+");

但是为什么你对你的第二个 sql 参数使用相同的值呢? p2 在行设置为parts[i][j]

Scanner inn = new Scanner(parts[i][j]).useDelimiter("[^0-9]+");

(记住:j 也以 0 开头)见行

for (j=0; j<parts[1].length; j++) {

所以你读了两次parts[i][0]

第二个问题可能是for循环变量j的上限:你将它设置为parts[1].length。这不应该是parts[i].length吗?

你怎么能解决它?看看你的值p1p2,也许你可以记录下来。这些是您期望的值吗? 你有哪些限制?只有主键还是boardno 也有约束或唯一索引(请参阅错误消息)?

你可以试试这样的:

try {
   rows = stmt.executeUpdate();
} catch (Exception e) {
   logger.error("p1="+p1+" p2="+p2+" catched="+e);
}

【讨论】:

  • 我没有为两个 sql 参数读取相同的值。请注意,在for (j=0; j&lt;parts[1].length; j++) 之后有一个if 语句if (parts[i][j].contains("MN")),我知道在我正在使用的文件中,包含字符串“MN”的部分永远不会出现在第一列中(即parts[i][0 ])。我使用其他输入文件在表中有正确的值。正是这个文件给了我错误。
  • 对不起,我不能。公司政策。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
  • 2011-02-16
  • 1970-01-01
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 2019-07-20
相关资源
最近更新 更多