Как я могу использовать обработку исключений при отправке повторяющихся значений в операторе вставки, если я отправляю много значений в пакетах? - PullRequest
0 голосов
/ 07 мая 2019

Я написал метод класса, который будет принимать «пакеты» данных (каждая строка, которая создает «значение» для вставки через базу данных в 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);
        }
    }

Ответы [ 2 ]

2 голосов
/ 07 мая 2019

Вставить или игнорировать

Просто измените (хотя на самом деле это не обработка исключений, а обход обходов)

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

т.е. 5 из 6 были добавлены 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 IGNORE вы можете использовать INSERT OR REPLACE .

например. следующее (запустить после вышеупомянутого, т.е. все биты дубликатов с разными данными): -

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-е и последнее обновление дважды в одной и той же строке).

1 голос
/ 07 мая 2019

Моим первым предложением будет дедупликация данных перед вставкой в ​​базу данных.( Редактировать : полностью пропущена часть "уже в БД", так что это, вероятно, не будет работать, если вы не хотите делать запрос перед каждой вставкой. Может быть, вы можете использовать INSERT IGNORE?)

Если вы не можете сделать это, потому что у вас нет контроля над первичным ключом или нет способа игнорировать дубликаты во вставке, тогда есть способы перехватить определенные типы исключений и продолжить программу вместо вызова System.exit,Для этого вам, вероятно, понадобится подготовить операторы меньшего размера и поместить try / catch внутри цикла for над data_values.

Вот сообщение о перехвате исключения такого типа: Поймать исключение вставки дубликата ключа .

...