Статьи

Spring Boot Hibernate Советы

1. Обзор

Hibernate не нуждается в представлении. Это самый популярный ORM для Java.

Аналогичным образом Spring Boot является наиболее мощной и простой в использовании инфраструктурой для Java.

Это руководство не о Hibernate или Spring Boot, их множество.

Мы рассмотрим некоторые распространенные ошибки, с которыми вы можете столкнуться при совместном использовании, и способы их устранения.

2. Зависимости

Мы будем использовать Gradle для создания нашего проекта. Я рекомендую использовать Spring Initializr для начальной загрузки вашего проекта.

Мы будем использовать:

  • Spring Boot 2
  • Spring Webflux
  • Spring Data JPA
  • Spring Data Envers
  • Джексон Аннотации
  • Джексон DataType Hibernate
  • База данных H2
  • Ломбок

Spring Data Envers позволяет нам получить доступ к ревизиям сущностей, управляемым Hibernate Envers.

Аннотации Джексона помогут нам избежать распространенных ошибок переполнения стека, вызванных отношениями JPA.

Модуль Jackson DataType Hibernate поможет с типами Hibernate и аспектами отложенной загрузки.

Мы рассмотрим все это через некоторое время.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
buildscript {
    ext {
        springBootVersion = '2.0.6.RELEASE'
    }
...
}
 
dependencies {
    implementation('org.springframework.boot:spring-boot-starter-data-jpa')
    implementation('org.springframework.boot:spring-boot-starter-webflux')
    implementation("org.springframework.data:spring-data-envers")
    implementation("com.fasterxml.jackson.core:jackson-annotations:2.9.7")
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:2.9.7")
    runtimeOnly('com.h2database:h2')
    compileOnly('org.projectlombok:lombok')
...
}

Мы будем использовать H2, чтобы запустить наш проект.

3. Сущности

В этом примере мы будем использовать JPA для создания университетов и студентов.

Всегда полезно хранить общую логику и свойства в суперклассе.

Мы создадим суперкласс для наших сущностей и будем хранить в нем общие свойства.

Давайте посмотрим на наш класс BaseEntity.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE)
@MappedSuperclass
@EntityListeners({AuditingEntityListener.class})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public abstract class BaseEntity {
    @Id
    @GeneratedValue
    Long id;
 
    @CreatedDate
    LocalDateTime createdAt;
    @LastModifiedDate
    LocalDateTime updatedAt;
}

Вы можете заметить, что я не использовал аннотацию @Data от Lombok в нашем классе. Аннотация @Data автоматически добавляет аннотацию @ToString которая может вызвать ошибки переполнения стека. Следовательно, лучше управлять аннотациями вручную.

Аннотация @MappedSuperclass позволяет объектам наследовать свойства от базового класса. Эта аннотация очень важна, если вы хотите наследовать свойства от базового класса.

@EntityListeners({AuditingEntityListener.class}) включает аудит. Мы используем @CreatedDate & @LastModifiedDate для захвата, когда объект был создан или изменен. Об этом позаботится Spring Data JPA.

@JsonIdentityInfo позволит избежать ошибок переполнения стека при преобразовании наших сущностей в JSON.
Эта аннотация требуется, чтобы разорвать бесконечный цикл из-за двунаправленных отношений между нашими объектами.

Вы также можете проверить @JsonBackReference & @JsonManagedReference чтобы убедиться, что они лучше соответствуют вашим требованиям.

Давайте посмотрим на наши университетские и студенческие организации.

1
2
3
4
5
6
7
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder @FieldDefaults(level = AccessLevel.PRIVATE)
@Entity @Audited
public class Student extends BaseEntity{
    String name;
    @ManyToOne
    University university;
}
1
2
3
4
5
6
7
8
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder @FieldDefaults(level = AccessLevel.PRIVATE)
@Entity @Audited
public class University extends BaseEntity{
    String name;
    String city;
    @OneToMany(mappedBy = "university")
    Set<Student> students = new HashSet<>();
}

@Audited позволит Hibernate управлять аудитом (отслеживанием изменений) на этом объекте.

4. Конфигурация

Давайте проверим конфигурации, необходимые для запуска нашего проекта.

4.1. Спящий модуль Джексона

1
2
3
4
@Bean
public Module hibernateModule(){
    return new Hibernate5Module();
}

Мы регистрируем новый модуль Джексона.
Spring Boot автоматически обнаружит его и зарегистрирует в ObjectMapper .

4.2. Спящий Энверс

Чтобы включить аудит Envers, мы должны расширить наши репозитории с помощью RevisionRepository .

Давайте посмотрим на наш репозиторий UniversityRepository .

1
2
public interface UniversityRepository extends RevisionRepository<University, Long, Long>, JpaRepository<University,Long> {
}

Мы должны сделать то же самое для нашего StudentRepository .

1
2
public interface StudentRepository extends RevisionRepository<Student, Long, Long>, JpaRepository<Student,Long> {
}

Мы также должны аннотировать наш основной класс с помощью @EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) .

Мы рассмотрим основной класс через некоторое время, пройдя другие аннотации, которые нам нужны.

4,3. Spring Data Auditing

Чтобы включить это, нам нужно аннотировать наш основной класс с помощью @EnableJpaAuditing .

Давайте посмотрим на это.

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableJpaAuditing
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
public class HibernateTipsApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(HibernateTipsApplication.class, args);
    }
}

5. Заключение

Я попытался объяснить на простом примере, как создавать REST-приложения, используя Spring Boot & Hibernate.

Это может решить некоторые из ваших ошибок переполнения стека.
Иначе, вы можете подумать о написании своих собственных объектов передачи данных (DTO).

Если вам нужна поддержка типов данных, которые не поддерживаются ядром Hibernate ORM, вы можете воспользоваться этой библиотекой .

Вы можете прочитать больше о:

Вы можете найти полный пример на Github .