Подтвердить что ты не робот

Разница между @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>();
4b9b3361

Ответ 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")