hibernate-fetch-mode-demo

This commit is contained in:
ydvorzhetskiy
2019-03-27 23:12:08 +03:00
parent 05d08b1f3e
commit 6620521317
19 changed files with 443 additions and 1 deletions
+2 -1
View File
@@ -3,4 +3,5 @@
## Описание проектов
* *unit-testing-plain-spring* - пример тестирования в проектах на чистом Spring
* *unit-testing-spring-boot* - то же самое, только на Spring Boot
* *unit-testing-spring-boot* - то же самое, только на Spring Boot
* *hibernate-fetch-mode-demo* - демонстрация настроек Hibernate, в частности для решения проблемы N+1
+29
View File
@@ -0,0 +1,29 @@
HELP.md
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/
### VS Code ###
.vscode/
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ru.otus.example</groupId>
<artifactId>hibernate-fetch-mode-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HibernateFetchModeDemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell-starter</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
@@ -0,0 +1,13 @@
package ru.otus.example.HibernateFetchModeDemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HibernateFetchModeDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HibernateFetchModeDemoApplication.class, args);
}
}
@@ -0,0 +1,21 @@
package ru.otus.example.HibernateFetchModeDemo.models;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "knowledge")
public class Knowledge {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String name;
}
@@ -0,0 +1,31 @@
package ru.otus.example.HibernateFetchModeDemo.models;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import javax.persistence.*;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "mentors")
public class Mentor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String name;
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany(targetEntity = Knowledge.class, cascade = CascadeType.ALL)
@JoinTable(name = "mentors_experience",
joinColumns = @JoinColumn(name = "mentor_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "knowledge_id", referencedColumnName = "id"))
private List<Knowledge> experience;
}
@@ -0,0 +1,34 @@
package ru.otus.example.HibernateFetchModeDemo.models;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import javax.persistence.*;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String name;
//@BatchSize(size = 5)
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany(targetEntity = Knowledge.class, cascade = CascadeType.ALL)
@JoinTable(name = "students_experience",
joinColumns = @JoinColumn(name = "student_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "knowledge_id", referencedColumnName = "id"))
private List<Knowledge> experience;
}
@@ -0,0 +1,34 @@
package ru.otus.example.HibernateFetchModeDemo.models;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import javax.persistence.*;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "teachers")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String name;
@LazyCollection(LazyCollectionOption.FALSE)
@Fetch(FetchMode.SUBSELECT)
@ManyToMany(targetEntity = Knowledge.class, cascade = CascadeType.ALL)
@JoinTable(name = "teachers_experience",
joinColumns = @JoinColumn(name = "teacher_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "knowledge_id", referencedColumnName = "id"))
private List<Knowledge> experience;
}
@@ -0,0 +1,9 @@
package ru.otus.example.HibernateFetchModeDemo.repositories;
import ru.otus.example.HibernateFetchModeDemo.models.Mentor;
import java.util.List;
public interface MentorRepository {
List<Mentor> findAll();
}
@@ -0,0 +1,20 @@
package ru.otus.example.HibernateFetchModeDemo.repositories;
import org.springframework.stereotype.Repository;
import ru.otus.example.HibernateFetchModeDemo.models.Mentor;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Repository
public class MentorRepositoryImpl implements MentorRepository {
@PersistenceContext
private EntityManager em;
@Override
public List<Mentor> findAll() {
return em.createQuery("select m from Mentor m join fetch m.experience", Mentor.class).getResultList();
}
}
@@ -0,0 +1,9 @@
package ru.otus.example.HibernateFetchModeDemo.repositories;
import ru.otus.example.HibernateFetchModeDemo.models.Student;
import java.util.List;
public interface StudentRepository {
List<Student> findAll();
}
@@ -0,0 +1,20 @@
package ru.otus.example.HibernateFetchModeDemo.repositories;
import org.springframework.stereotype.Repository;
import ru.otus.example.HibernateFetchModeDemo.models.Student;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Repository
public class StudentRepositoryImpl implements StudentRepository {
@PersistenceContext
private EntityManager em;
@Override
public List<Student> findAll() {
return em.createQuery("select s from Student s", Student.class).getResultList();
}
}
@@ -0,0 +1,9 @@
package ru.otus.example.HibernateFetchModeDemo.repositories;
import ru.otus.example.HibernateFetchModeDemo.models.Teacher;
import java.util.List;
public interface TeacherRepository {
List<Teacher> findAll();
}
@@ -0,0 +1,20 @@
package ru.otus.example.HibernateFetchModeDemo.repositories;
import org.springframework.stereotype.Repository;
import ru.otus.example.HibernateFetchModeDemo.models.Teacher;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Repository
public class TeacherRepositoryImpl implements TeacherRepository {
@PersistenceContext
private EntityManager em;
@Override
public List<Teacher> findAll() {
return em.createQuery("select t from Teacher t", Teacher.class).getResultList();
}
}
@@ -0,0 +1,48 @@
package ru.otus.example.HibernateFetchModeDemo.shell;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import ru.otus.example.HibernateFetchModeDemo.models.Mentor;
import ru.otus.example.HibernateFetchModeDemo.models.Student;
import ru.otus.example.HibernateFetchModeDemo.models.Teacher;
import ru.otus.example.HibernateFetchModeDemo.repositories.MentorRepository;
import ru.otus.example.HibernateFetchModeDemo.repositories.StudentRepository;
import ru.otus.example.HibernateFetchModeDemo.repositories.TeacherRepository;
import java.util.stream.Collectors;
@ShellComponent
public class ShellCommands {
private static final String OFFSET = "\n\n----------------------------\n\n";
private final StudentRepository studentRepository;
private final MentorRepository mentorRepository;
private final TeacherRepository teacherRepository;
public ShellCommands(StudentRepository studentRepository, MentorRepository mentorRepository, TeacherRepository teacherRepository) {
this.studentRepository = studentRepository;
this.mentorRepository = mentorRepository;
this.teacherRepository = teacherRepository;
}
@ShellMethod(value = "Show all students", key = "find-all-students")
public String findAllStudents(){
System.out.println();
return OFFSET + studentRepository.findAll().stream().map(Student::toString).collect(Collectors.joining("\n"));
}
@ShellMethod(value = "Show all mentors", key = "find-all-mentors")
public String findAllMentors(){
System.out.println();
return OFFSET + mentorRepository.findAll().stream().map(Mentor::toString).collect(Collectors.joining("\n"));
}
@ShellMethod(value = "Show all teachers", key = "find-all-teachers")
public String findAllTeachers(){
System.out.println();
return OFFSET + teacherRepository.findAll().stream().map(Teacher::toString).collect(Collectors.joining("\n"));
}
}
@@ -0,0 +1,15 @@
spring:
datasource:
url: jdbc:h2:mem:testdb
initialization-mode: always
jpa:
generate-ddl: false
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
#format_sql: true
@@ -0,0 +1,9 @@
INSERT INTO knowledge (name) VALUES ('Spring Core'), ('Spring Data'), ('Spring MVC'), ('Spring Batch'), ('Spring Integration'), ('Spring WebFlux');
INSERT INTO students (name) VALUES ('Student #01'), ('Student #02'), ('Student #03'), ('Student #04'), ('Student #05'), ('Student #06'), ('Student #07'), ('Student #08'), ('Student #09');
INSERT INTO mentors (name) VALUES ('Mentor #01'), ('Mentor #02'), ('Mentor #03'), ('Mentor #04'), ('Mentor #05'), ('Mentor #06'), ('Mentor #07'), ('Mentor #08'), ('Mentor #09');
INSERT INTO teachers (name) VALUES ('Teacher #01'), ('Teacher #02'), ('Teacher #03'), ('Teacher #04'), ('Teacher #05'), ('Teacher #06'), ('Teacher #07'), ('Teacher #08'), ('Teacher #09');
INSERT INTO students_experience (student_id, knowledge_id) VALUES (1, 1), (1, 2), (2, 2), (2, 3), (2, 4), (2, 5);
INSERT INTO mentors_experience (mentor_id, knowledge_id) VALUES (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6);
INSERT INTO teachers_experience (teacher_id, knowledge_id) VALUES(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6);
@@ -0,0 +1,48 @@
DROP TABLE IF EXISTS students_experience;
DROP TABLE IF EXISTS mentors_experience;
DROP TABLE IF EXISTS teachers_experience;
DROP TABLE IF EXISTS students;
DROP TABLE IF EXISTS mentors;
DROP TABLE IF EXISTS teachers;
DROP TABLE IF EXISTS knowledge;
CREATE TABLE knowledge (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
);
CREATE TABLE students (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
);
CREATE TABLE mentors (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
);
CREATE TABLE teachers (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
);
CREATE TABLE students_experience (
student_id BIGINT,
knowledge_id BIGINT,
FOREIGN KEY(student_id) REFERENCES students(id) ON DELETE CASCADE,
FOREIGN KEY(knowledge_id) REFERENCES knowledge(id) ON DELETE CASCADE
);
CREATE TABLE mentors_experience (
mentor_id BIGINT,
knowledge_id BIGINT,
FOREIGN KEY(mentor_id) REFERENCES mentors(id) ON DELETE CASCADE,
FOREIGN KEY(knowledge_id) REFERENCES knowledge(id) ON DELETE CASCADE
);
CREATE TABLE teachers_experience (
teacher_id BIGINT,
knowledge_id BIGINT,
FOREIGN KEY(teacher_id) REFERENCES teachers(id) ON DELETE CASCADE,
FOREIGN KEY(knowledge_id) REFERENCES knowledge(id) ON DELETE CASCADE
);
@@ -0,0 +1 @@