Я пытаюсь вставить несколько слов в базу данных и вернуть вновь вставленный идентификатор или существующий идентификатор, если это слово уже находится в базе данных.Как вставить (или существующие) идентификаторы с executeBatch()
Я нашел, что могу сделать это, используя PreparedStatement
и включая Statement.RETURN_GENERATED_KEYS
. Но PreparedStatement
ужасно медленный. Мне нужно вставить как 5000 слов сразу. Другой способ, которым я мог бы добиться этого, выполнив отдельного запроса в течение цикла:
public ArrayList<Integer> addWords(ArrayList<String[]> allTermsForTag) {
ArrayList ids = new ArrayList<Integer>();
ResultSet rs = null;
try{
Statement st = connection.createStatement();
for (String[] articleTerms: allTermsForTag) {
for(String term: articleTerms) {
String query = "WITH a AS (INSERT INTO tag (name) SELECT '"+term+"' WHERE NOT EXISTS (SELECT name FROM tag WHERE name = '"+term+"') " +
"RETURNING id) SELECT id FROM a UNION SELECT id FROM tag WHERE name = '"+term+"'";
rs = st.executeQuery(query);
while (rs.next())
{
int id = rs.getInt(1);
ids.add(id);
System.out.printf("id: "+id);
}
}
}
rs.close();
st.close();
}catch(SQLException e){
System.out.println("SQL exception was raised while performing SELECT: "+e);
}
return ids;
}
Это делает то, что мне нужно красиво, но это слишком медленно, как хорошо.
Другой метод, который я написал использует executeBatch()
, однако, он не возвращает идентификаторы:
public ArrayList<Integer> addWords(ArrayList<String[]> allTermsForTag){
ResultSet rs = null;
ArrayList ids = new ArrayList<Integer>();
try{
Statement st = connection.createStatement();
for (String[] articleTerms: allTermsForTag) {
for(String term: articleTerms) {
String query = "WITH a AS (INSERT INTO tag (name) SELECT '"+term+"' WHERE NOT EXISTS (SELECT name FROM tag WHERE name = '"+term+"') " +
"RETURNING id) SELECT id FROM a UNION SELECT id FROM tag WHERE name = '"+term+"'";
st.addBatch(query);
}
st.executeBatch();
rs = st.getGeneratedKeys();
while (rs.next()) {
int id = rs.getInt(1);
ids.add(id);
}
}
st.close();
return ids;
}catch (SQLException e){
System.out.println("SQL exception was raised while performing batch INSERT: "+e.getNextException());
System.out.println("dub");
}
return null;
}
Таким образом, вопрос - как получить идентификаторы при использовании executeBatch()
или, если это невозможно, как подойти к этому проблема? Мне нужно, чтобы он работал как можно быстрее, потому что в INSERT будет много операций с большим объемом данных. Спасибо!
Благодарим вас за ответ. Это некоторые продвинутые вещи, о которых вы говорите) Не знакомы с большинством из них, но попытаются выяснить. Итак, если у меня есть таблица с моими данными, я КОПИРУЮ ее в таблицу temp? Затем сделайте - INSERT INTO ... SELECT ... RETURNING ... введите временную таблицу, не так ли? И я полагаю, все это должно быть сделано в транзакции? – Sermilion
@Sermilion Yep, почти все. В противном случае вы можете попробовать только последний драйвер jdbc и пакетную вставку с сгенерированными ключами. Это будет довольно немного медленнее, но, вероятно, достаточно быстро. –
Ну, я добавил драйвер версии 9.4-1201-jdbc4. Это дает мне ту же ошибку: org.postgresql.util.PSQLException: результат был возвращен, когда никто не ожидал. Не могли бы вы посмотреть на код для executeBatch() и посмотреть, что все в порядке. Или, может быть, я добавил неправильную версию jdbc? Спасибо . – Sermilion