如果我批量发送多个值,如何在插入语句中发送重复值时使用异常处理?
How can I use exception handling while sending duplicate values in an insert statement, if I'm sending many values in batches?
我写了一个 class 方法,它将获取 "batches" 数据(构成 "value" 的每一行将通过 SQL 插入到数据库来自标记为 "data_values").
的二维数组
但是,有时我的程序会获取冗余数据,即可能已经在数据库中的数据。因为数据库中有一个主键,如果由于重复条目而无法上传数据,程序就会中断。
有没有办法使用 try/catch 让程序继续上传数据,有效地 "skipping" 重复?如果是这样,我该如何实施?
提前谢谢你。如果我能澄清我的问题,请告诉我。
我当前的代码在这里:
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);
}
}
我的第一个建议是在将数据插入数据库之前删除重复数据。 (编辑:完全错过了 "already in the db" 部分,所以这可能行不通,除非你想在每次插入之前进行查询。也许你可以使用 INSERT IGNORE
?)
如果因为无法控制主键或无法忽略插入中的重复项而无法执行此操作,则有一些方法可以捕获特定的异常类型并继续执行程序,而不是调用 System.exit
。为了做到这一点,你可能需要有更小的准备语句并将 try/catch 放在 for 循环中的 'data_values` 上。
这里有一个post在谈论捕获这种类型的异常:Catch duplicate key insert exception。
插入或忽略
只需更改(虽然不是真正的异常处理,而是异常绕过)
String insertDataScript = "INSERT INTO "+tableName+" VALUES (";
至
String insertDataScript = "INSERT OR IGNORE INTO "+tableName+" VALUES (";
考虑以下演示(相当于建议,然后是您当前拥有的):-
rowid 是为了方便而使用的,因为它基本上是内置主键。
指定列的唯一原因,即 (rowid,othercolumn,mydatecolumn)
是 rowid 通常是隐藏的。在您的情况下,只有 VALUES(没有前面的列)将期望所有列的值,因此包括定义的主键列。
shown/actioned 顺序相反,因为两者都可以 运行 在一起
:-
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
即none 由于 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 行更新为第一行和最后一次更新同一行两次)。
我写了一个 class 方法,它将获取 "batches" 数据(构成 "value" 的每一行将通过 SQL 插入到数据库来自标记为 "data_values").
的二维数组但是,有时我的程序会获取冗余数据,即可能已经在数据库中的数据。因为数据库中有一个主键,如果由于重复条目而无法上传数据,程序就会中断。
有没有办法使用 try/catch 让程序继续上传数据,有效地 "skipping" 重复?如果是这样,我该如何实施?
提前谢谢你。如果我能澄清我的问题,请告诉我。
我当前的代码在这里:
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);
}
}
我的第一个建议是在将数据插入数据库之前删除重复数据。 (编辑:完全错过了 "already in the db" 部分,所以这可能行不通,除非你想在每次插入之前进行查询。也许你可以使用 INSERT IGNORE
?)
如果因为无法控制主键或无法忽略插入中的重复项而无法执行此操作,则有一些方法可以捕获特定的异常类型并继续执行程序,而不是调用 System.exit
。为了做到这一点,你可能需要有更小的准备语句并将 try/catch 放在 for 循环中的 'data_values` 上。
这里有一个post在谈论捕获这种类型的异常:Catch duplicate key insert exception。
插入或忽略
只需更改(虽然不是真正的异常处理,而是异常绕过)
String insertDataScript = "INSERT INTO "+tableName+" VALUES (";
至
String insertDataScript = "INSERT OR IGNORE INTO "+tableName+" VALUES (";
考虑以下演示(相当于建议,然后是您当前拥有的):-
rowid 是为了方便而使用的,因为它基本上是内置主键。
指定列的唯一原因,即
(rowid,othercolumn,mydatecolumn)
是 rowid 通常是隐藏的。在您的情况下,只有 VALUES(没有前面的列)将期望所有列的值,因此包括定义的主键列。shown/actioned 顺序相反,因为两者都可以 运行 在一起
:-
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
即none 由于 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 行更新为第一行和最后一次更新同一行两次)。