Счетчик GeneratedValue для Id сбрасывается каждый раз, когда выполняются сервер и клиент.

Я работаю над приложением JavaEE с EJB и JPA.

Мои сущности определяются, например, так:

@Entity
public class Utente implements Serializable {

@Id
@GeneratedValue
private int cod_utente;
private String nome_utente;
private String morada_utente;
@Temporal(TemporalType.DATE)
private GregorianCalendar dnasc_utente;
private int tel_utente;
private List<GregorianCalendar> agenda;
@OneToMany
@JoinColumn(nullable=true)
private List<Prescricao> lista_presc;

Когда я создаю объекты Utente, ключи генерируются последовательно, начиная с одного. Если я выключаю клиентов и сервер и запускаю их снова, "счетчик" генератора ключей восстанавливается. Это приводит к ошибке, поскольку приложение попытается создать еще один Utente с первичным ключом "1".

Может ли кто-нибудь помочь мне решить эту проблему?


person Ghost    schedule 01.01.2015    source источник
comment
АФАИК должно работать. Пробовали ли вы вручную установить другую стратегию генерации?   -  person SJuan76    schedule 01.01.2015
comment
Кстати, какой поставщик JPA? Какая система БД? Установлены ли свойства JPA для этого диалекта?   -  person SJuan76    schedule 01.01.2015
comment
Я использую стеклянную рыбку. Поставщик JPA — EclipseLink.   -  person Ghost    schedule 02.01.2015


Ответы (1)


Код:

@Id
@GeneratedValue
private int cod_utente;

не устанавливает конкретную стратегию для создания значений для идентификатора.

Это то же самое, что и этот код:

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int cod_utente;

GenerationType.AUTO означает, что поставщик сохраняемости (в Glassfish поставщиком сохраняемости по умолчанию является EclipseLink) следует выбрать соответствующую стратегию для используемой базы данных. Похоже, что поставщик постоянства выбирает стратегию, которая перезапускает значения после перезапуска сервера в вашем случае.

Существуют различные стратегии генерации. Подробную информацию можно найти в EclipseLink Wiki. .

Я думаю, вам лучше всего использовать последовательность базы данных (GenerationType.SEQUENCE) для генерации значений идентификатора.

Пример:

Создайте последовательность базы данных с именем GEN_SEQUENCE (если вы позволите поставщику постоянства сгенерировать ваши таблицы, я думаю, вы также можете позволить ему каким-то образом создать последовательность, но этот пример покажет, как сделать это вручную), вы должны искать информацию о том, как это сделать в базу данных, которую вы используете (вероятно, что-то вроде CREATE SEQUENCE gen_sequence;). Измените свой код на это:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq_gen")
@SequenceGenerator(name = "my_seq_gen", sequenceName = "GEN_SEQUENCE")
private int cod_utente;

Вы также можете использовать одну и ту же последовательность для разных классов.

Обновление:

Для @SequenceGenerator можно установить locationSize, это значение представляет собой количество зарезервированных значений последовательности. Значение по умолчанию — 50. Если у вас есть последовательность, начинающаяся с 0, при первом запросе значения из последовательности последовательность выделяет (и резервирует) значения 0–49 (или 1–50). Эти значения могут использоваться поставщиком постоянства до тех пор, пока не будут использованы все значения, после чего будут выделены и зарезервированы следующие 50 значений (50-99 или 51-100). Последовательность запоминает текущую позицию, поэтому она не выдает один и тот же диапазон дважды, если она используется несколькими классами.

Для значения allocationSize можно оставить значение по умолчанию, но это может привести к пробелам в идентификаторах. Если диапазон последовательности (например, 0-49) выделяется (зарезервирован) и используется только одно или несколько значений (например, 0, 1 и 2), другие значения этого диапазона (3-49) будут "потеряны" на перезапуск сервера. В следующий раз, когда будет выделен диапазон значений, он будет 50-99, поэтому следующий идентификатор в вашей таблице будет 50.
Теперь у вас есть следующие идентификаторы в вашей таблице: 0,1,2,50. Обычно это не должно быть проблемой, но вы также можете установить allocationSize на более низкое значение или на 1, чтобы избежать создания таких пробелов.

См. также:

person unwichtich    schedule 01.01.2015
comment
чтобы использовать эту стратегию, нам нужно правильно установить allocationSize? Чему соответствует это значение? по какому критерию установить это значение? - person Ghost; 02.01.2015
comment
Я написал этот код в своих объектах: @Id @SequenceGenerator(name="seq7", initialValue=1, allocationSize=100) @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq7") private int cod_ficha; Но эта ошибка произошла при запуске сервера: xception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLSyntaxErrorException: SEQUENCE 'SEQ7' does not exist. Error Code: 30000 Call: VALUES(NEXT VALUE FOR seq7) Query: ValueReadQuery(sql="VALUES(NEXT VALUE FOR seq7)") - person Ghost; 02.01.2015
comment
Сообщение об ошибке говорит, что последовательность не существует. Как описано в ответе, вы должны создать последовательность вручную в базе данных. - person unwichtich; 02.01.2015