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:
commit
6637d1a95a
|
@ -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)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- More articles: [[<-- prev]](../spring-boot-persistence-2)
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 + '\'' + '}';
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
logging.level.org.hibernate:
|
||||
SQL: DEBUG
|
||||
type.descriptor.sql.BasicBinder: TRACE
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue