diff --git a/spring-caching/pom.xml b/spring-caching/pom.xml
index 80644f8a5f..5a320d3048 100644
--- a/spring-caching/pom.xml
+++ b/spring-caching/pom.xml
@@ -58,6 +58,20 @@
org.springframework.boot
spring-boot-starter-jdbc
+
+ org.projectlombok
+ lombok
+ 1.18.12
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.data
+ spring-data-commons
+ 2.3.0.RELEASE
+
3.5.2
diff --git a/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java b/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java
new file mode 100644
index 0000000000..7de567f0db
--- /dev/null
+++ b/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java
@@ -0,0 +1,21 @@
+package com.baeldung.springdatacaching.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.UUID;
+
+@Data
+@Entity
+@NoArgsConstructor
+@AllArgsConstructor
+public class Book {
+
+ @Id
+ private UUID id;
+ private String title;
+
+}
diff --git a/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java b/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java
new file mode 100644
index 0000000000..d7f80b8b57
--- /dev/null
+++ b/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java
@@ -0,0 +1,15 @@
+package com.baeldung.springdatacaching.repositories;
+
+import com.baeldung.springdatacaching.model.Book;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.repository.CrudRepository;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public interface BookRepository extends CrudRepository {
+
+ @Cacheable(value = "books", unless="#a0=='Foundation'")
+ Optional findFirstByTitle(String title);
+
+}
diff --git a/spring-caching/src/main/resources/data.sql b/spring-caching/src/main/resources/data.sql
deleted file mode 100644
index e4165ae71f..0000000000
--- a/spring-caching/src/main/resources/data.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-INSERT INTO CUSTOMER VALUES(1001,'BAELDUNG');
-
-INSERT INTO ITEM VALUES(10001,'ITEM1',50.0);
-INSERT INTO ITEM VALUES(10002,'ITEM2',100.0);
-
-INSERT INTO ORDERDETAIL VALUES(300001,1001,10001,2);
-INSERT INTO ORDERDETAIL VALUES(300002,1001,10002,5);
\ No newline at end of file
diff --git a/spring-caching/src/main/resources/schema.sql b/spring-caching/src/main/resources/schema.sql
deleted file mode 100644
index 5862499bc0..0000000000
--- a/spring-caching/src/main/resources/schema.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-CREATE TABLE CUSTOMER(
- CUSTOMERID INT PRIMARY KEY,
- CUSTOMERNAME VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE ITEM(
-ITEMID INT PRIMARY KEY,
-ITEMDESC VARCHAR(250),
-PRICE DOUBLE
-);
-
-CREATE TABLE ORDERDETAIL(
-ORDERID INT PRIMARY KEY,
-CUSTOMERID INT NOT NULL,
-ITEMID INT NOT NULL,
-QUANTITY INT,
-FOREIGN KEY (customerid) references CUSTOMER(customerid),
-FOREIGN KEY (itemid) references ITEM(itemid)
-);
\ No newline at end of file
diff --git a/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java
new file mode 100644
index 0000000000..49ecc3a058
--- /dev/null
+++ b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java
@@ -0,0 +1,86 @@
+package com.baeldung.springdatacaching.repositories;
+
+import com.baeldung.springdatacaching.model.Book;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.util.AopTestUtils;
+
+import java.util.UUID;
+
+import static java.util.Optional.of;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration
+@ExtendWith(SpringExtension.class)
+public class BookRepositoryCachingIntegrationTest {
+
+ private static final Book DUNE = new Book(UUID.randomUUID(), "Dune");
+ private static final Book FOUNDATION = new Book(UUID.randomUUID(), "Foundation");
+
+ private BookRepository mock;
+
+ @Autowired
+ private BookRepository bookRepository;
+
+ @EnableCaching
+ @Configuration
+ public static class CachingTestConfig {
+
+ @Bean
+ public BookRepository bookRepositoryMockImplementation() {
+ return mock(BookRepository.class);
+ }
+
+ @Bean
+ public CacheManager cacheManager() {
+ return new ConcurrentMapCacheManager("books");
+ }
+
+ }
+
+ @BeforeEach
+ void setUp() {
+ mock = AopTestUtils.getTargetObject(bookRepository);
+
+ reset(mock);
+
+ when(mock.findFirstByTitle(eq("Foundation")))
+ .thenReturn(of(FOUNDATION));
+
+ when(mock.findFirstByTitle(eq("Dune")))
+ .thenReturn(of(DUNE))
+ .thenThrow(new RuntimeException("Book should be cached!"));
+ }
+
+ @Test
+ void givenCachedBookWhenFindByTitleThenRepositoryShouldNotBeHit() {
+ assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune"));
+ verify(mock).findFirstByTitle("Dune");
+
+ assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune"));
+ assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune"));
+
+ verifyNoMoreInteractions(mock);
+ }
+
+ @Test
+ void givenNotCachedBookWhenFindByTitleThenRepositoryShouldBeHit() {
+ assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation"));
+ assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation"));
+ assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation"));
+
+ verify(mock, times(3)).findFirstByTitle("Foundation");
+ }
+
+}
diff --git a/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..56bc898bd0
--- /dev/null
+++ b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java
@@ -0,0 +1,58 @@
+package com.baeldung.springdatacaching.repositories;
+
+import com.baeldung.caching.boot.CacheApplication;
+import com.baeldung.springdatacaching.model.Book;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cache.CacheManager;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.Optional;
+import java.util.UUID;
+
+import static java.util.Optional.empty;
+import static java.util.Optional.ofNullable;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@ExtendWith(SpringExtension.class)
+@EntityScan(basePackageClasses = Book.class)
+@SpringBootTest(classes = CacheApplication.class)
+@EnableJpaRepositories(basePackageClasses = BookRepository.class)
+public class BookRepositoryIntegrationTest {
+
+ @Autowired
+ CacheManager cacheManager;
+
+ @Autowired
+ BookRepository repository;
+
+ @BeforeEach
+ void setUp() {
+ repository.save(new Book(UUID.randomUUID(), "Dune"));
+ repository.save(new Book(UUID.randomUUID(), "Foundation"));
+ }
+
+ @Test
+ void givenBookThatShouldBeCachedWhenFindByTitleThenResultShouldBePutInCache() {
+ Optional dune = repository.findFirstByTitle("Dune");
+
+ assertEquals(dune, getCachedBook("Dune"));
+ }
+
+ @Test
+ void givenBookThatShouldNotBeCachedWhenFindByTitleThenResultShouldNotBePutInCache() {
+ repository.findFirstByTitle("Foundation");
+
+ assertEquals(empty(), getCachedBook("Foundation"));
+ }
+
+ private Optional getCachedBook(String title) {
+ return ofNullable(cacheManager.getCache("books")).map(c -> c.get(title, Book.class));
+ }
+
+}