Статьи

Идентификаторы в спящем режиме

Вступление:

Идентификаторы в Hibernate моделируют атрибут первичного ключа объекта. Это помогает нам однозначно идентифицировать объект JPA. Каждая сущность должна определить идентификатор. Также он может быть простым или составным.

Мы можем определить идентификатор Hibernate несколькими способами. В этом уроке мы узнаем, как это сделать.

Простой (однозначный) идентификатор:

Если у нас есть один атрибут, который может однозначно идентифицировать нашу сущность, мы можем просто аннотировать этот атрибут аннотацией @Id :

Ява

1
2
3
4
5
6
7
8
@Entity
public class Employee {
  
    @Id
    private Integer empId;
      
    ...
}

Пожалуйста, помните, что атрибут, аннотируемый @Id, должен быть одного из следующих типов:

  • любой примитивный тип Java или любой тип примитивной оболочки
  • строка
  • любой из типов даты Java, или
  • BigDecimal или BigInteger

Простые генерируемые идентификаторы:

Что если мы хотим, чтобы наши значения идентификаторов генерировались автоматически? Для этого мы можем пойти дальше и использовать аннотацию @GeneratedValue в нашем поле идентификатора:

Ява

1
2
3
4
5
6
7
8
@Entity
public class Employee {
     
    @Id
    @GeneratedValue
    public Integer empId;
    ...
}

При использовании @GeneratedValue Hibernate генерирует значение для нашего столбца id , сохраняя при этом сущность. Нам важно помнить, что мы можем автоматически генерировать только целочисленный тип ( int, short или long ) или UUID .

Кроме того, у нас есть четыре различных стратегии генерации ключей для автоматической генерации значения нашего идентификатора:

1. Стратегия AUTO Generation:

Hibernate по умолчанию использует стратегию генерации ключей AUTO . Поведение стратегии AUTO немного варьируется от одного поставщика устойчивости JPA к другому. В случае Hibernate, если атрибут идентификатора имеет тип UUID, он использует UUIDGenerator или по умолчанию использует стратегию генерации последовательности.

Генерация UUID поддерживается только в Hibernate 5 и более поздних версиях и имеет длину 36 символов:

Ява

1
2
3
4
5
6
7
8
9
@Entity
public class Employee {
  
    @Id
    @GeneratedValue
    private UUID empId;
  
    ...
}

Сгенерированный UUID имеет форму ‘4ee5a777-7981-4e01-06ab-19aabb2eaa122’.

2. ИДЕНТИЧНОСТЬ Стратегия генерации:

Для стратегии генерации IDENTITY Hibernate использует IdentityGenerator для генерации значений идентификаторов . Значения генерируются столбцом идентификаторов базы данных и автоматически увеличиваются:

Ява

1
2
3
4
5
6
7
8
9
@Entity
public class Employee {
  
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private Integer empId;
  
    ...
}

Основным недостатком использования этой стратегии является то, что она не поддерживает пакетные вставки JDBC.

3. ПОСЛЕДОВАТЕЛЬНОСТЬ Стратегия генерации:

Здесь, как следует из названия, последовательности базы данных используются для генерации значений для нашего идентификатора. Hibernate использует класс SequenceStyleGenerator для достижения этой цели. Если наша база данных не поддерживает последовательности, она автоматически переключается на стратегию генерации ключей TABLE .

Генератор SEQUENCE генерирует уникальные значения для каждой последовательности. Мы можем указать последовательность базы данных, которую мы хотим использовать:

Ява

01
02
03
04
05
06
07
08
09
10
11
@Entity
public class Employee {
     
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
      generator = "emp_generator")
    @SequenceGenerator(name = "emp_generator",
      sequenceName = "emp_seq", allocationSize = 100)
    public Integer empId;
    ...
}

Или Hibernate будет использовать неявно названную последовательность hibernate_sequence :

Ява

1
2
3
4
5
6
7
8
@Entity
public class Employee {
     
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    public Integer empId;
    ...
}

генерировать значения для нашего поля идентификатора.

4. ТАБЛИЦА Поколение Стратегия:

Hibernate TableGenerator использует таблицу, способную содержать несколько сегментов значений генерации идентификатора. Если не указано иное, Hibernate по умолчанию использует таблицу hibernate_sequence :

Ява

1
2
3
4
5
6
7
8
@Entity
public class Employee {
     
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    public Integer empId;
    ...
}

Мы можем использовать @TableGenerator, чтобы указать таблицу базы данных, которая будет использоваться для генерации значений:

Ява

01
02
03
04
05
06
07
08
09
10
11
12
13
@Entity
    public class Employee {
  
        @Id
        @GeneratedValue(strategy = GenerationType.TABLE, generator = "emp_generator")
        @TableGenerator(name = "emp_generator",
          table = "emp_generator_tbl",
          schema = "employees")
        public Integer empId;
         
        ...
  
 }

Стратегия TABLE не очень масштабируема и имеет низкую производительность, поэтому вряд ли используется в реальных реализациях. Мы всегда должны предпочитать использовать стратегию генерации SEQUENCE для всех баз данных, которые поддерживают последовательности, что чаще всего делают все современные базы данных.

Составные идентификаторы:

Hibernate также позволяет нам определять составной идентификатор. Чтобы определить составной идентификатор, мы создаем класс первичного ключа, содержащий постоянные атрибуты, которые формируют наш составной ключ. В соответствии со спецификациями JPA наш класс первичного ключа должен быть:

  1. Аннотируется аннотациями @EmbeddedId или @IdClass
  2. публичный и общедоступный конструктор без аргументов
  3. Сериализуемый
  4. Реализация методов equals () и hashCode ()

Атрибуты, составляющие композицию, могут быть базовыми, составными или ManyToOne. Однако коллекции и атрибуты OneToOne не считаются подходящими.

1. Используя @EmbeddedId:

Одним из способов определения и использования составного ключа является использование аннотации @EmbeddedId .

Итак, давайте начнем с определения нашего класса первичного ключа и аннотирования его с помощью @Embeddable :

Ява

1
2
3
4
5
6
7
8
9
@Embeddable
public class EmployeePurchasesPK implements Serializable {
  
    private long empId;
    private long productId;
  
    //equals() and hashCode() methods
    ...
}

Теперь мы можем легко ссылаться на этот класс из нашей сущности, используя аннотацию @EmbeddedId :

Ява

1
2
3
4
5
6
7
8
@Entity
public class EmployeePurchases {
  
    @EmbeddedId
    private EmployeePurchasesPK primaryAttributes;
  
    ...
}

Чтобы использовать наш класс сущностей для установки или получения атрибутов первичного ключа, у нас будет что-то вроде:

Ява

1
2
3
4
5
6
7
EmployeePurchasesPK primaryAttributes = new EmployeePurchasesPK();
primaryAttributes.setEmpId(1001);
primaryAttributes.setProductId(7822);
  
EmployeePurchases empPurchases = new EmployeePurchases();
empPurchases.setPrimaryAttributes(primaryAttributes);
...

Очевидно, что наша сущность EmployeePurchases имеет составной ключ, состоящий из empId и productId .

2. Использование @IdClass :

При использовании @IdClass для создания составного ключа мы можем использовать аннотацию @Id для определения всех наших атрибутов композиции в нашем основном классе. Код в нашем классе первичного ключа остается как есть, но он действует только как «тень» :

Ява

01
02
03
04
05
06
07
08
09
10
11
12
13
@Entity
@IdClass(EmployeePurchasesPK.class)
public class EmployeePurchases {
  
    @Id
    private long empId;
  
    @Id
    private long productId;
  
    ...
  
}

При таком подходе мы можем напрямую устанавливать значения ключей, используя методы получения / установки нашего основного класса сущностей:

Ява

1
2
3
4
EmployeePurchases empPurchases = new EmployeePurchases();
empPurchases.setEmpId(1011);
empPurchases.setProductId(9331);
...

Однако этот метод не дает нам четкого разделения между идентификатором и объектом нашей сущности.

Производные идентификаторы:

В Hibernate мы можем скопировать значение идентификатора объекта из одной из его ассоциаций, используя аннотацию @MapsId :

Ява

01
02
03
04
05
06
07
08
09
10
11
12
public class EmployeeHistory {
  
    @Id
    private long id;
  
    @OneToOne
    @MapsId
    private Employee employee;
  
    ...
  
}

Здесь наш экземпляр EmployeeHistory будет иметь тот же идентификатор, что и соответствующий экземпляр Employee .

Вывод:

В этом руководстве мы рассмотрели несколько способов определения идентификатора в Hibernate. Мы также рассмотрели различные стратегии автоматической генерации ключей.

Оставьте первый комментарий.

Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Идентификаторы в Hibernate

Мнения, высказанные участниками Java Code Geeks, являются их собственными.