Sql ошибка с уникальностю id

577
06 февраля 2017, 15:53

Когда пытаюсь вставить id в поле возникает уникальность. Извлекал через resultset id и приболял в конце id+=1;,но не работает. Если не трудно обьясните почему не извлекаются данные до последний записи в id. И как сделать что бы id генерировался автоматически БД postgresql.

Код repository.

public void Add(String First_Name, String Last_Name, String Second_Name, String email, String password, String login) {
        Date date = new Date();
        SimpleDateFormat format1 = new SimpleDateFormat("dd.MM.yyyy");
        String sqlDate = format1.format(date);
        int id = 0;
        Connection c = getCurrentConnection();
        QueryRunner queryRunner = new QueryRunner();
        try {
            Statement statement = c.createStatement();
            ResultSet resultSet = statement.executeQuery("SELECT id FROM  account  ");
            while (resultSet.next()) {
                id = resultSet.getInt("id");
            }
            id += 1;
            String sql = "insert into account (id,login,password,first_name,last_name,second_name,email,active,created) values(" + "'" + id + "'" + "," +
                    "'" + login + "'" + "," + "'" + password + "'" + "," + "'" + First_Name + "'" + "," + "'" + Last_Name + "'" + "," + "'" +
                    Second_Name + "'" + "," + "'" + email + "'" + "," + "'" + "true" + "'" + "," + "'" + sqlDate + "'" + ")";
            queryRunner.update(c, sql);
            queryRunner.update(c, "insert into account_role (id,id_account,id_role) values " +
                    "(" + "'" + id + "'" + "," + "'" + id + "'" + "," + "'" + 1 + "'" + ")");
        } catch (SQLException e) {
            throw new WebtesterApplicationException(e);
        }
    }

Ошибка.

HTTP Status 500 - java.sql.SQLException: ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности "account_pkey"
type Exception report
message java.sql.SQLException: ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности "account_pkey"
description The server encountered an internal error that prevented it from fulfilling this request.
exception
exception.WebtesterApplicationException: java.sql.SQLException: ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности "account_pkey"
  Подробности: Ключ "(id)=(2)" уже существует. Query: insert into account (id,login,password,first_name,last_name,second_name,email,active,created) values('2','password','maximbogunwork@gmail.comw2','maksim','ascsav','','maksimbogunenko1z2','true','04.02.2017') Parameters: []
    repositoryimpl.AccountRegistrationImpl.Add(AccountRegistrationImpl.java:43)
    serviceimpl.CommonServiceImpl.registration(CommonServiceImpl.java:109)
    servlet.RegistrationServlet.doPost(RegistrationServlet.java:32)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    filter.CheckLoginFilter.doFilter(CheckLoginFilter.java:39)
    filter.AbstarctFilter.doFilter(AbstarctFilter.java:22)
    filter.AutoLoginFilter.doFilter(AutoLoginFilter.java:45)
    filter.AbstarctFilter.doFilter(AbstarctFilter.java:22)
root cause
java.sql.SQLException: ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности "account_pkey"
  Подробности: Ключ "(id)=(2)" уже существует. Query: insert into account (id,login,password,first_name,last_name,second_name,email,active,created) values('2','password','maximbogunwork@gmail.comw2','maksim','ascsav','','maksimbogunenko1z2','true','04.02.2017') Parameters: []
    org.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392)
    org.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:491)
    org.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:377)
    repositoryimpl.AccountRegistrationImpl.Add(AccountRegistrationImpl.java:39)
    serviceimpl.CommonServiceImpl.registration(CommonServiceImpl.java:109)
    servlet.RegistrationServlet.doPost(RegistrationServlet.java:32)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    filter.CheckLoginFilter.doFilter(CheckLoginFilter.java:39)
    filter.AbstarctFilter.doFilter(AbstarctFilter.java:22)
    filter.AutoLoginFilter.doFilter(AutoLoginFilter.java:45)
    filter.AbstarctFilter.doFilter(AbstarctFilter.java:22)
Answer 1

Записи Вашим запросом SELECT Id FROM account выводятся, вообще говоря, в случайном порядке. Поэтому последний id из ResultSet не обязательно будет последним использованным.

Можно заменить запрос на такой SELECT Id FROM account ORDER BY Id. Тогда гарантированно последний id будет действительно последним.

Но лучше такой SELECT MAX(Id) FROM account. Не трудно догадаться, что извлечь id сразу гораздо лучше перебора 100500-и строк.

Но и это лажа, годная в очень специфических случаях. Для генерации Id с давних пор применяются последовательности (иногда используется термин генератор).

Сначала в базе создаётся последовательность: create sequence id_seq. Следующий номер извлекается функцией nextval(): select nextval('id_seq'). Каждый вызов nextval() возвращает новый номер больший прошлого на единицу (кстати приращение можно настраивать).

Есть несколько способов записать номер из последовательности в поле.
1) Предварительно извлечь запросом
id = select nextval('id_seq')
insert into table (id, ...) values (id, ...)
2) Использовать nextval() в запросе insert
insert into table (id, ...) values (nextval('id_seq'), ...)
3) объявит поле id со значением по умолчанию
create table (id int default nextval('id_seq'), ...
В запросе insert поле id не трогать insert into table (...) values (...)
4) И ещё один способ - поле id объявить как serial create table (id serial, ... Это является сокращением объявления последовательности и значения по умолчанию. Т.е. в этом не надо объявлять ни последовательность, ни значение по умолчанию.

В случаях 2, 3, 4 имеются некоторые трудности определения какой id получила новая запись, если он вдруг нужен дальше в программе. Поэтому первый способ более распространённый. Но тем не менее есть способ узнать новый id используя запрос такого вида insert into table (...) values (...) returning id. Запрос вставит запись и вернёт её id.

Answer 2

Вам надо делать

SELECT MAX(Id) FROM account
READ ALSO
Разработка игры на Java [требует правки]

Разработка игры на Java [требует правки]

Мой вопрос: есть ли разница при написании игры на java под пк и андроид? Стоит ли мне смотреть курсы по разработке игры на пк если я хочу делать...

497
Найти факториал числа с применением BigInteger

Найти факториал числа с применением BigInteger

Условие задачи: Реализуйте метод, вычисляющий факториал заданного натурального числаФакториал NN вычисляется как 1⋅2⋅

575
Code Style for OOP [дубликат]

Code Style for OOP [дубликат]

На данный вопрос уже ответили:

449
Как программно запретить “Overlay scrollbar” в Ubuntu

Как программно запретить “Overlay scrollbar” в Ubuntu

Я пытаюсь портировать на Ubuntu свое приложение, построенное на SWT, и столкнулся с проблемой с тназ

472