Разница между @GeneratedValue и @GenericGenerator
Иногда я нахожу их вместе, иногда одни... в других случаях они, похоже, делают то же самое.
Какая разница?
Вот три примера. Что они делают из разных? Почему я не могу использовать только @GeneratedValue для всех из них?
Пример 1
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
Long id;
Пример 2
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE)
private int userId;
Пример 3
@ElementCollection
@JoinTable(name="Address",
[email protected](name="user_id")
)
@GenericGenerator(name="hilo-gen", strategy="hilo")
@CollectionId(columns = @Column(name="Address_id"), generator = "hilo-gen", type = @Type(type="long"))
Collection<Addr> listOfAddresses = new ArrayList<Addr>();
Ответы
Ответ 1
При использовании ORM часто необходимо генерировать значение первичного ключа.
Аннотация @GeneratedValue
означает, что генерируется значение для столбца, которое должно быть аннотировано с помощью @Id
. Элементы strategy
и generator
в аннотации описывают, как получается полученное значение.
Существует четыре возможных значения для элемента strategy
в аннотации @GeneratedValue
: IDENTITY
, AUTO
, TABLE
и SEQUENCE
. Подробнее.
Чтобы ответить на Часть 2 вашего вопроса, фрагмент кода указывает, что значение userId
будет получено через последовательность в базе данных.
Элемент generator
аннотации @GeneratedValue
обозначает имя первичного генератора ключей. В Part1 вашего вопроса фрагмент кода указывает, что для получения значения первичного ключа будет использоваться generator
с именем increment
. increment
затем определяется в следующей аннотации @GenericGenerator
. @GenericGenerator
- аннотация спящего режима, используемая для обозначения пользовательского генератора, который может быть классом или ярлыком для генератора, поставляемого Hibernate. increment
- это ярлык для генератора спящего режима, который:
генерирует идентификаторы типа long, short или int, которые являются уникальными только когда другой процесс не вставляет данные в ту же таблицу. Не использовать в кластере.
В Третьей части вашего вопроса, код использует генератор hilo
Hibernate, который:
использует алгоритм hi/lo для эффективного генерации идентификаторов типа long, short или int, учитывая таблицу и столбец (по умолчанию hibernate_unique_key и next_hi соответственно) в качестве источника привет значения. Алгоритм hi/lo генерирует только уникальные идентификаторы для конкретной базы данных.
Ответ 2
@Entity
@Table(name="Honey")
public class Honey implements Serializable{
private static final long serialVersionUID = 42L;
@Id
//@SequenceGenerator(name="honeySequence",sequenceName="HONEY_SEQ")
@org.hibernate.annotations.GenericGenerator(name="honeySequence", strategy = "sequence",
parameters = {
@Parameter(name="sequence", value="HONEY_SEQ") }
)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="honeySequence")
private int Id;
private String name;
private String taste;
- @GeneratedValue используется только для получения сгенерированного значения. Два аргумента стратегия и генератор используются для определения способа получения значения.
- @GenericGenerator используется для отображения генерируемого пользователем генератора последовательности с сеансом спящего режима.
- Вы также можете использовать @SequenceGenerator, который я прокомментировал в своем коде. Это не простой генератор последовательности, а генератор, который работает с алгоритмом HILO. Из-за чего вы найдете много пробелов в своей последовательности, например, ваше первое значение начнется с 50, потому что размер распределения по умолчанию равен 50.
Поэтому лучше использовать @GenericGenerator для вашей собственной архитектуры. Но если вы обязаны использовать @SequenceGenerator, вам нужно вручную изменить свою последовательность, чтобы иметь еще два атрибута allocSize = 1 и initialValue = 1. И для работы с этими атрибутами вам нужно добавить apropert в файл hibernate.cfg.xml
<property name="hibernate.id.new_generator_mappings">true</property>
Ответ 3
Чтобы продлить ответ @kevin-bowersox.
Отношения между стратегиями генерации первичного ключа Hibernate и конкретным генератором соответственно, как указано в org.hibernate.id.IdentifierGeneratorFactory
static {
GENERATORS.put("uuid", UUIDHexGenerator.class);
GENERATORS.put("hilo", TableHiLoGenerator.class);
GENERATORS.put("assigned", Assigned.class);
GENERATORS.put("identity", IdentityGenerator.class);
GENERATORS.put("select", SelectGenerator.class);
GENERATORS.put("sequence", SequenceGenerator.class);
GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);
GENERATORS.put("increment", IncrementGenerator.class);
GENERATORS.put("foreign", ForeignGenerator.class);
GENERATORS.put("guid", GUIDGenerator.class);
GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated
GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);
}
Вышеупомянутые двенадцать стратегий плюс native
- это тринадцать стратегий генерации, поддерживаемых по умолчанию в Hibernate.
Пример с native
:
@GeneratedValue(generator = "nativeGenerator")
@GenericGenerator(name = "nativeGenerator", strategy = "native")