From 2c1e17244e1ee15f9f0520f4639402da4af25d37 Mon Sep 17 00:00:00 2001 From: Shay Keren Date: Tue, 5 Aug 2025 10:06:41 +0300 Subject: [PATCH 1/4] Fix N+1 query issue by adding eager fetching method for vets with specialties --- .../samples/petclinic/vet/VetRepository.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java index 8b9e0823c86..726085d19cf 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java @@ -19,10 +19,9 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collection; +import org.springframework.transaction.annotation.Transactional;import java.util.Collection; /** * Repository class for Vet domain objects All method names are compliant @@ -34,7 +33,8 @@ * @author Juergen Hoeller * @author Sam Brannen * @author Michael Isvy - */ + */import org.springframework.data.jpa.repository.Query; + public interface VetRepository extends Repository { /** @@ -55,4 +55,9 @@ public interface VetRepository extends Repository { @Cacheable("vets") Page findAll(Pageable pageable) throws DataAccessException; -} + @Query("SELECT v FROM Vet v LEFT JOIN FETCH v.specialties") + @Transactional(readOnly = true) + @Cacheable("vets") + List findAllWithSpecialties() throws DataAccessException; + +} \ No newline at end of file From f30a4f97e06a3b9c36fac95f677f13b6d408cbe1 Mon Sep 17 00:00:00 2001 From: Shay Keren Date: Tue, 5 Aug 2025 10:07:23 +0300 Subject: [PATCH 2/4] Fix N+1 query issue in showResourcesVetList by using findAllWithSpecialties method --- .../samples/petclinic/vet/VetController.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java b/src/main/java/org/springframework/samples/petclinic/vet/VetController.java index 3240814a6f1..bea31de642e 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/VetController.java @@ -15,9 +15,7 @@ */ package org.springframework.samples.petclinic.vet; -import java.util.List; - -import org.springframework.data.domain.Page; +import java.util.List;import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Controller; @@ -32,8 +30,7 @@ * @author Ken Krebs * @author Arjen Poutsma */ -@Controller -class VetController { +@Controllerclass VetController { private final VetRepository vetRepository; @@ -58,9 +55,7 @@ private String addPaginationModel(int page, Page paginated, Model model) { model.addAttribute("totalItems", paginated.getTotalElements()); model.addAttribute("listVets", listVets); return "vets/vetList"; - } - - private Page findPaginated(int page) { + }private Page findPaginated(int page) { int pageSize = 5; Pageable pageable = PageRequest.of(page - 1, pageSize); return vetRepository.findAll(pageable); @@ -71,8 +66,8 @@ private Page findPaginated(int page) { // Here we are returning an object of type 'Vets' rather than a collection of Vet // objects so it is simpler for JSon/Object mapping Vets vets = new Vets(); - vets.getVetList().addAll(this.vetRepository.findAll()); + vets.getVetList().addAll(this.vetRepository.findAllWithSpecialties()); return vets; } -} +} \ No newline at end of file From ffc02a72a933d16bdf2b1d0af39cd5ad370839ed Mon Sep 17 00:00:00 2001 From: Shay Keren Date: Tue, 5 Aug 2025 10:07:54 +0300 Subject: [PATCH 3/4] Add paginated query method for vets endpoint with specialties fetch --- .../samples/petclinic/vet/VetRepository.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java index 726085d19cf..377c814254a 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java @@ -13,9 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; - -import org.springframework.cache.annotation.Cacheable; +package org.springframework.samples.petclinic.vet;import org.springframework.cache.annotation.Cacheable; import org.springframework.dao.DataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -33,9 +31,7 @@ * @author Juergen Hoeller * @author Sam Brannen * @author Michael Isvy - */import org.springframework.data.jpa.repository.Query; - -public interface VetRepository extends Repository { + */import org.springframework.data.jpa.repository.Query;public interface VetRepository extends Repository { /** * Retrieve all Vets from the data store. @@ -60,4 +56,9 @@ public interface VetRepository extends Repository { @Cacheable("vets") List findAllWithSpecialties() throws DataAccessException; + @Query("SELECT v FROM Vet v LEFT JOIN FETCH v.specialties") + @Transactional(readOnly = true) + @Cacheable("vets") + Page findAllWithSpecialties(Pageable pageable) throws DataAccessException; + } \ No newline at end of file From f804341f761cf09032a55b3979340d77da3646cc Mon Sep 17 00:00:00 2001 From: Shay Keren Date: Tue, 5 Aug 2025 10:08:23 +0300 Subject: [PATCH 4/4] Fix N+1 query issue in findPaginated method by using findAllWithSpecialties --- .../samples/petclinic/vet/VetController.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java b/src/main/java/org/springframework/samples/petclinic/vet/VetController.java index bea31de642e..a00cf002c9b 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/VetController.java @@ -13,9 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; - -import java.util.List;import org.springframework.data.domain.Page; +package org.springframework.samples.petclinic.vet;import java.util.List;import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Controller; @@ -36,9 +34,7 @@ public VetController(VetRepository clinicService) { this.vetRepository = clinicService; - } - - @GetMapping("/vets.html") + }@GetMapping("/vets.html") public String showVetList(@RequestParam(defaultValue = "1") int page, Model model) { // Here we are returning an object of type 'Vets' rather than a collection of Vet // objects so it is simpler for Object-Xml mapping @@ -58,10 +54,8 @@ private String addPaginationModel(int page, Page paginated, Model model) { }private Page findPaginated(int page) { int pageSize = 5; Pageable pageable = PageRequest.of(page - 1, pageSize); - return vetRepository.findAll(pageable); - } - - @GetMapping({ "/vets" }) + return vetRepository.findAllWithSpecialties(pageable); + }@GetMapping({ "/vets" }) public @ResponseBody Vets showResourcesVetList() { // Here we are returning an object of type 'Vets' rather than a collection of Vet // objects so it is simpler for JSon/Object mapping