Java PreparedStatement метод executeBatch генерирует уникальное ограничение для первичного ключа - PullRequest
0 голосов
/ 15 апреля 2020

Я написал метод addContacts для своего класса DatabaseUtilities для использования в моем приложении обмена сообщениями. Соответствующие таблицы базы данных: учетные записи , контакты и accountContact . Я добавил последнее в моей попытке 3NF. При выполнении кода через тестовый жгут JUnit, обнаруженный ниже, я получаю эту ошибку:

не удалось добавить контакты: [SQLITE_CONSTRAINT_PRIMARYKEY] Сбой ограничения PRIMARY KEY (Сбой ограничения UNIQUE: accountContact.uid, accountContact. cid)

Я пытался закомментировать код, ответственный за остановку автоматической фиксации, полагая, что проблема может быть вызвана неправильной фиксацией, но это не проблема. Мне известно, что это SQL работает при непосредственном использовании в базе данных sqlite, при этом контакты сначала добавляются один за другим, а затем в accountContact записываются следующие.

Следующий код - мой метод addContacts:

  boolean addContacts(List<Contact> contacts, Account account) {
    try {
        try {
            conn.setAutoCommit(false);

            queryInsertContact.clearParameters();
            queryInsertAccountContact.clearParameters();

            for (Contact contact : contacts) {
                if (ipv4Pattern.matcher(contact.getIpv4()).matches() && contact.getAlias().length() <= 256 &&
                        contact.getTlsPort() >= 1024 && contact.getTlsPort() <= 65535) {
                    queryInsertContact.setString(1, contact.getCid());
                    queryInsertContact.setString(2, contact.getAlias());
                    queryInsertContact.setString(3, contact.getIpv4());
                    queryInsertContact.setInt(4, contact.getTlsPort());
                    queryInsertContact.addBatch();

                    queryInsertAccountContact.setInt(1, account.getUid());
                    queryInsertAccountContact.setString(2, contact.getCid());
                    queryInsertAccountContact.addBatch();
                } else {
                    throw new SQLException("Format incorrect");
                }
            }

            queryInsertContact.executeBatch();
            queryInsertAccountContact.executeBatch(); // THE TEST HARNESS FAILS HERE

            conn.commit();
            return true;

        } catch (SQLException e) {

            System.out.println("failed to add contacts: " + e.getMessage());
            conn.rollback();
        } finally {
            conn.setAutoCommit(true);
        }
    } catch (SQLException e) {
    }

    return false;
}

Следующий код - мой тестовый комплект addContacts:

 @org.junit.Test
public void addContacts() {

    List<Contact> contacts = new ArrayList<>();

    try {
        byte[] salt = getSalt(), hashWithSalt = getKey(salt, "password");
        String stringSalt = Base64.getEncoder().encodeToString(salt);
        String tempHash = Base64.getEncoder().encodeToString(hashWithSalt);

        Account account = new Account("james", tempHash, stringSalt, 100000);
        Contact contact = new Contact("abc", "accountboi", "127.0.0.1", 1025);
        databaseUtilities.addAccount(account, contact);

        try { // THIS CODE JUST GETS THE ACCOUNT INSTANCE WITH ITS UID DEFAULT WAS -1
            account = databaseUtilities.getAccount(account.getUsername());
        }catch (SQLException e){}

        contacts.add(new Contact("f1dg13d7f8sfd", "nrmad", "127.0.0.1", 1025));
    assertTrue(databaseUtilities.addContacts(contacts, account));

    contacts.clear();
    contacts.add(new Contact("f1dg13d7f8sfd", "nrmad", "127.0.0.1", 1025));
    assertFalse(databaseUtilities.addContacts(contacts, account));

    contacts.clear();
    contacts.add(new Contact("f1dg13d7f8sfd1", "nrmad", "1234-0-0-1", 1025));
    assertFalse(databaseUtilities.addContacts(contacts, account));

    contacts.clear();
    contacts.add(new Contact("f1dg13d7f8sfd2", "nrmad", "127-a-a-a", 1));
    assertFalse(databaseUtilities.addContacts(contacts, account));

    contacts.clear();
    contacts.add(new Contact("f1dg13d7f8sfd3", "nrmad", "127.0.0.0", 65536));
    assertFalse(databaseUtilities.addContacts(contacts, account));

    contacts.clear();
    contacts.add( new Contact("f1dg13d7f8sfd4", "nrmad", "127-a-a-a", -1));
    assertFalse(databaseUtilities.addContacts(contacts, account));

    // UP TO HERE EVERYTHING IS WORKING. THE FOLLOWING CODE IS WHERE THE ERROR IS THROWN        

    contacts.clear();
    contacts.add(new Contact("a1", "nrmad", "127.0.0.1", 1025));
    contacts.add(new Contact("a2", "nrmad", "127.0.0.1", 1025));
    contacts.add(new Contact("a3", "nrmad", "127.0.0.1", 1025));

    assertTrue(databaseUtilities.addContacts(contacts, account)); // THIS STATEMENT


    }catch(NoSuchAlgorithmException |InvalidKeySpecException e){
        System.out.println(e.getMessage());
    }
}

Следующие операторы SQL представляют собой дамп учетных записей , контактов и accountContact таблиц соответственно:

CREATE TABLE contacts(cid TEXT PRIMARY KEY, alias TEXT NOT NULL, ipv4 TEXT NOT NULL, tlsport INTEGER NOT NULL);
CREATE TABLE accounts(uid INTEGER PRIMARY KEY, username TEXT NOT NULL, pass TEXT NOT NULL, salt TEXT NOT NULL, iterations INTEGER NOT NULL);
CREATE TABLE accountContact( uid INTEGER, cid TEXT, PRIMARY KEY(uid, cid), FOREIGN KEY (uid) REFERENCES accounts(uid),FOREIGN KEY (cid) REFERENCES contacts(cid));

Эти SQL операторы используются для инициализации подготовленных операторов, использованных в приведенном выше коде

private static final String INSERT_CONTACT = "INSERT INTO contacts(cid, alias, ipv4, tlsport) VALUES(?,?,?,?)";
private static final String INSERT_ACCOUNT = "INSERT INTO accounts(uid, username, pass, salt, iterations) VALUES(?,?,?,?,?)";
private static final String INSERT_ACCOUNTCONTACT = "INSERT INTO accountContact(uid, cid) VALUES(?,?)";

Это сбило меня с толку Хотя и любая помощь будет оценена.

Спасибо

1 Ответ

0 голосов
/ 16 апреля 2020

Я использовал метод clearParameters () метода PreparedStatement, полагая, что он будет сбрасывать объект после каждого теста метода addContacts (), однако есть отдельный метод, который делает это для пакетов clearBatch ()

...