如果我分批发送许多值,如何在插入语句中发送重复值时使用异常处理?

Posted

技术标签:

【中文标题】如果我分批发送许多值,如何在插入语句中发送重复值时使用异常处理?【英文标题】:How can I use exception handling while sending duplicate values in an insert statement, if I'm sending many values in batches? 【发布时间】:2019-05-06 23:30:13 【问题描述】:

我编写了一个类方法,它将获取“批量”数据(通过 SQL 将“值”插入数据库的每一行都来自一个标有“data_values”的二维数组)。

但是,在某些情况下,我的程序会获取冗余数据,即可能已经在数据库中的数据。由于数据库中有一个主键,如果由于重复条目而无法上传数据,程序将中断。

有没有办法使用 try/catch 以便程序继续上传数据,有效地“跳过”重复项?如果是这样,我该如何实施?

提前谢谢你。如果我能澄清我的问题,请告诉我。

我当前的代码在这里:

public void insertData(ArrayList<String> data_types, String[][] data_values) 

        try    
            c.setAutoCommit(false); 
            // creates insert statement
            String insertDataScript = "INSERT INTO "+tableName+" VALUES (";
            for(int q = 0; q < data_types.size()-1; q++) 
                insertDataScript += "?, ";
            
            insertDataScript += "?)";

            PreparedStatement stmt = c.prepareStatement(insertDataScript);
            for (int i = 0; i < data_values.length; i++) 

                for(int j = 1; j < data_types.size()+1; j++) 

                    if(data_types.get(j-1).toLowerCase().equals("double")) 
                        stmt.setDouble(j, Double.valueOf(data_values[i][j-1]));
                    
                    else if(data_types.get(j-1).toLowerCase().equals("string")) 
                        stmt.setString(j, data_values[i][j-1]);
                    
                    else 
                        System.out.println("Error");
                    
                
                stmt.addBatch();
            
            stmt.executeBatch();
            c.commit();
            c.setAutoCommit(true);
            stmt.close();
         
        catch ( Exception e ) 
            System.err.println( e.getClass().getName() + ": " + e.getMessage() );
            System.exit(0);
        
    

【问题讨论】:

主键是自己创建还是由数据库处理?如果是,它会自动递增吗? 我建议将逻辑放到数据库中。根据this answer,这可能就像在您的SQL 语句中添加OR REPLACE 一样简单——但由于我从未使用过sqlite,我无法确认。 我自己创建了主键,并将相应地更新帖子。我不相信它是自动递增的,因为我没有明确地创建这样的表。 【参考方案1】:

我的第一个建议是在将数据插入数据库之前对其进行重复数据删除。 (编辑:完全错过了“已经在数据库中”部分,所以除非您想在每次插入之前进行查询,否则这可能行不通。也许您可以使用INSERT IGNORE?)

如果您因为无法控制主键或无法忽略插入中的重复项而无法执行此操作,则有办法捕获特定异常类型并继续程序,而不是调用System.exit。为了做到这一点,您可能需要准备更小的语句,并将 try/catch 放在 for 循环中的“data_values”上。

这是一篇关于捕获此类异常的帖子:Catch duplicate key insert exception。

【讨论】:

谢谢莉莉丝。我接受了您的回答,不仅因为 INSERT OR IGNORE INTO 是正确的解决方案,还因为您引用了异常处理链接,这正是我的想法。【参考方案2】:

插入或忽略

只需更改(虽然不是真正的异常处理,而是绕过异常)

String insertDataScript = "INSERT INTO "+tableName+" VALUES (";

String insertDataScript = "INSERT OR IGNORE INTO "+tableName+" VALUES (";

考虑以下演示(相当于建议的,然后是您当前拥有的):-

rowid 是为了方便起见而使用的,因为它基本上是内置的主键。

指定列的唯一原因,即(rowid,othercolumn,mydatecolumn) 是 rowid 通常是隐藏的。在您的情况下,只有 VALUES(没有前面的列)将期望所有列的值,因此包括定义的主键列。

以相反的顺序显示/执行,因为两者可以一起运行

:-

INSERT OR IGNORE INTO mytable (rowid,othercolumn,mydatecolumn) -- rowid is a PRIMARY KEY as such
    VALUES
        (10,'x','x'),
        (11,'x','x'),
        (12,'x','x'),
        (13,'x','x'),
        (14,'x','x'),
        (10,'x','x')
;

INSERT INTO mytable (rowid,othercolumn,mydatecolumn) -- rowid is a PRIMARY KEY as such
    VALUES
        (20,'x','x'),
        (21,'x','x'),
        (22,'x','x'),
        (23,'x','x'),
        (24,'x','x'),
        (20,'x','x')
;

结果:-

INSERT OR IGNORE INTO mytable (rowid,othercolumn,mydatecolumn) -- rowid is a PRIMARY KEY as such
    VALUES
        (10,'x','x'),
        (11,'x','x'),
        (12,'x','x'),
        (13,'x','x'),
        (14,'x','x'),
        (10,'x','x')
> Affected rows: 5
> Time: 0.208s

即6 个中的 5 个被添加到第 6 个重复项(根据主键)被跳过。

INSERT INTO mytable (rowid,othercolumn,mydatecolumn) -- rowid is a PRIMARY KEY as such
    VALUES
        (20,'x','x'),
        (21,'x','x'),
        (22,'x','x'),
        (23,'x','x'),
        (24,'x','x'),
        (20,'x','x')
> UNIQUE constraint failed: mytable.rowid
> Time: 0.006s

即由于 1 个重复,没有插入任何内容。

插入或替换(可能有用)

如果您希望应用来自重复项的数据,则可以使用 INSERT OR REPLACE 而不是 INSERT OR IGNORE

例如以下(在上述之后运行,即所有都是具有不同数据的重复位):-

INSERT OR REPLACE INTO mytable (rowid,othercolumn,mydatecolumn) -- rowid is a PRIMARY KEY as such
    VALUES
        (10,'xx','x'),
        (11,'x','xx'),
        (12,'aa','x'),
        (13,'x','aa'),
        (14,'x','bb'),
        (10,'cc','x')
;

然后你得到:-

INSERT OR REPLACE INTO mytable (rowid,othercolumn,mydatecolumn) -- rowid is a PRIMARY KEY as such
    VALUES
        (10,'xx','x'),
        (11,'x','xx'),
        (12,'aa','x'),
        (13,'x','aa'),
        (14,'x','bb'),
        (10,'cc','x')
> Affected rows: 6
> Time: 0.543s

即现在所有 6 个 INSERT 都已执行(第 5 行更新为第 1 行,最后一次更新同一行两次)。

【讨论】:

非常感谢您的详细回复。我最终选择了insert or ignore into 解决方案。

以上是关于如果我分批发送许多值,如何在插入语句中发送重复值时使用异常处理?的主要内容,如果未能解决你的问题,请参考以下文章

通过 sqlalchemy 关系添加值时如何避免插入重复条目?

SQL执行插入时,遇到重复键值时,如何设置才能让新插入的数据覆盖原有旧数据;要用存储过程么?

提交值时如何在 React 挂钩中使用回调函数?

如何发送表单输入值并调用 JSF bean 中的方法

在php中将最后一个id插入变量发送到另一个页面[重复]

当 API 中未发送必填字段值时,如何在 swagger 中自定义错误消息?