diff --git a/persistence-modules/spring-boot-persistence-3/HELP.md b/persistence-modules/spring-boot-persistence-3/HELP.md new file mode 100644 index 0000000000..d5a5463718 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/HELP.md @@ -0,0 +1,9 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/{bootVersion}/reference/htmlsingle/#using-boot-devtools) +* [Spring Configuration Processor](https://docs.spring.io/spring-boot/docs/{bootVersion}/reference/htmlsingle/#configuration-metadata-annotation-processor) + diff --git a/persistence-modules/spring-boot-persistence-3/README.md b/persistence-modules/spring-boot-persistence-3/README.md new file mode 100644 index 0000000000..1dff3c8b5a --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- More articles: [[<-- prev]](../spring-boot-persistence-2) diff --git a/persistence-modules/spring-boot-persistence-3/pom.xml b/persistence-modules/spring-boot-persistence-3/pom.xml new file mode 100644 index 0000000000..b9d9d8b49a --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + com.baeldung.boot.persistence + spring-boot-persistence-3 + 0.0.1-SNAPSHOT + spring-boot-persistence-3 + + + com.baeldung + persistence-modules + 1.0.0-SNAPSHOT + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.dependencies} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 2.1.8.RELEASE + + + \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/LargeResultSetApplication.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/LargeResultSetApplication.java new file mode 100644 index 0000000000..d592894226 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/LargeResultSetApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.largeresultset; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LargeResultSetApplication { + + public static void main(String[] args) { + SpringApplication.run(LargeResultSetApplication.class, args); + } + +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/Student.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/Student.java new file mode 100644 index 0000000000..283d0f032d --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/Student.java @@ -0,0 +1,53 @@ +package com.baeldung.largeresultset; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Student { + + @Id + @GeneratedValue + private Long id; + + private String firstName; + private String lastName; + + public Student() { + } + + public Student(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "Student{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/StudentRepository.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/StudentRepository.java new file mode 100644 index 0000000000..bc3815fa84 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/StudentRepository.java @@ -0,0 +1,16 @@ +package com.baeldung.largeresultset; + +import java.util.stream.Stream; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface StudentRepository extends JpaRepository { + Slice findAllByFirstName(String firstName, Pageable page); + Page findAllByLastName(String firstName, Pageable page); + Stream findAllByFirstName(String firstName); +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/service/EmailService.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/service/EmailService.java new file mode 100644 index 0000000000..59169f66da --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/service/EmailService.java @@ -0,0 +1,14 @@ +package com.baeldung.largeresultset.service; + +import org.springframework.stereotype.Service; + +import com.baeldung.largeresultset.Student; + +@Service +public class EmailService { + + public void sendEmailToStudent(Student student) { + System.out.println("sending email to: " + student); + } + +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/service/StudentService.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/service/StudentService.java new file mode 100644 index 0000000000..e65fc34849 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/largeresultset/service/StudentService.java @@ -0,0 +1,62 @@ +package com.baeldung.largeresultset.service; + +import java.util.List; +import java.util.stream.Stream; + +import javax.persistence.EntityManager; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.largeresultset.Student; +import com.baeldung.largeresultset.StudentRepository; + +@Service +public class StudentService { + private static final int BATCH_SIZE = 5; + private final StudentRepository repository; + private final EmailService emailService; + private final EntityManager entityManager; + + public StudentService(StudentRepository repository, EmailService emailService, EntityManager entityManager) { + this.repository = repository; + this.emailService = emailService; + this.entityManager = entityManager; + } + + public void processStudentsByFirstName(String firstName) { + Slice slice = repository.findAllByFirstName(firstName, PageRequest.of(0, BATCH_SIZE)); + List studentsInBatch = slice.getContent(); + studentsInBatch.forEach(emailService::sendEmailToStudent); + + while (slice.hasNext()) { + slice = repository.findAllByFirstName(firstName, slice.nextPageable()); + slice.getContent() + .forEach(emailService::sendEmailToStudent); + } + } + + public void processStudentsByLastName(String lastName) { + Page page = repository.findAllByLastName(lastName, PageRequest.of(0, BATCH_SIZE)); + page.getContent() + .forEach(emailService::sendEmailToStudent); + + while (page.hasNext()) { + page = repository.findAllByLastName(lastName, page.nextPageable()); + page.getContent() + .forEach(emailService::sendEmailToStudent); + } + } + + @Transactional(readOnly = true) + public void processStudentsByFirstNameUsingStreams(String firstName) { + try (Stream students = repository.findAllByFirstName(firstName)) { + students.peek(entityManager::detach) + .forEach(emailService::sendEmailToStudent); + } + } + +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/resources/application.yml b/persistence-modules/spring-boot-persistence-3/src/main/resources/application.yml new file mode 100644 index 0000000000..bb9e377c34 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/resources/application.yml @@ -0,0 +1,4 @@ + +logging.level.org.hibernate: + SQL: DEBUG + type.descriptor.sql.BasicBinder: TRACE \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/largeresultset/LargeResultSetUnitTest.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/largeresultset/LargeResultSetUnitTest.java new file mode 100644 index 0000000000..95e1231707 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/largeresultset/LargeResultSetUnitTest.java @@ -0,0 +1,75 @@ +package com.baeldung.boot.largeresultset; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import com.baeldung.largeresultset.LargeResultSetApplication; +import com.baeldung.largeresultset.Student; +import com.baeldung.largeresultset.StudentRepository; +import com.baeldung.largeresultset.service.EmailService; +import com.baeldung.largeresultset.service.StudentService; + +@SpringBootTest(classes = LargeResultSetApplication.class) +class LargeResultSetUnitTest { + + @Autowired + private StudentRepository repository; + + @Autowired + private StudentService studentService; + + @MockBean + private EmailService mockEmailService; + + @AfterEach + public void afterEach() { + repository.deleteAll(); + } + + @Test + void givenTwelveRowsMatchingCriteria_whenRetrievingDataSliceBySlice_allDataIsProcessed() { + saveStudents(12); + + studentService.processStudentsByFirstName("john"); + + verify(mockEmailService, times(12)).sendEmailToStudent(any()); + } + + @Test + void givenTwelveRowsMatchingCriteria_whenRetrievingDataPageByPage_allDataIsProcessed() { + saveStudents(12); + + studentService.processStudentsByLastName("doe"); + + verify(mockEmailService, times(12)).sendEmailToStudent(any()); + } + + @Test + void processStudentsByFirstNameUsingStreams() { + saveStudents(12); + + studentService.processStudentsByFirstNameUsingStreams("john"); + + verify(mockEmailService, times(12)).sendEmailToStudent(any()); + } + + private void saveStudents(int count) { + List students = IntStream.range(0, count) + .boxed() + .map(i -> new Student("john", "doe")) + .collect(Collectors.toList()); + repository.saveAll(students); + } + +} \ No newline at end of file