Merge pull request #12829 from etrandafir93/features/BAEL-5736-large_results_spring_data_jpa

BAEL-5736: added new module and code snippets
This commit is contained in:
davidmartinezbarua 2022-10-06 22:08:57 -03:00 committed by GitHub
commit 6637d1a95a
10 changed files with 315 additions and 0 deletions

View File

@ -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)

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- More articles: [[<-- prev]](../spring-boot-persistence-2)

View File

@ -0,0 +1,66 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.boot.persistence</groupId>
<artifactId>spring-boot-persistence-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-persistence-3</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>persistence-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit-jupiter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.dependencies}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</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>
<properties>
<spring.boot.dependencies>2.1.8.RELEASE</spring.boot.dependencies>
</properties>
</project>

View File

@ -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);
}
}

View File

@ -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 + '\'' + '}';
}
}

View File

@ -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<Student, Long> {
Slice<Student> findAllByFirstName(String firstName, Pageable page);
Page<Student> findAllByLastName(String firstName, Pageable page);
Stream<Student> findAllByFirstName(String firstName);
}

View File

@ -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);
}
}

View File

@ -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<Student> slice = repository.findAllByFirstName(firstName, PageRequest.of(0, BATCH_SIZE));
List<Student> 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<Student> 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<Student> students = repository.findAllByFirstName(firstName)) {
students.peek(entityManager::detach)
.forEach(emailService::sendEmailToStudent);
}
}
}

View File

@ -0,0 +1,4 @@
logging.level.org.hibernate:
SQL: DEBUG
type.descriptor.sql.BasicBinder: TRACE

View File

@ -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<Student> students = IntStream.range(0, count)
.boxed()
.map(i -> new Student("john", "doe"))
.collect(Collectors.toList());
repository.saveAll(students);
}
}