diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 9b8a3b318a..1d8e82572b 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -91,6 +91,7 @@ spring-boot-redis spring-boot-cassandre spring-boot-react + spring-caching-3 spring-boot-3-grpc spring-boot-3-native diff --git a/spring-boot-modules/spring-caching-3/README.md b/spring-boot-modules/spring-caching-3/README.md new file mode 100644 index 0000000000..5429a0bb2f --- /dev/null +++ b/spring-boot-modules/spring-caching-3/README.md @@ -0,0 +1,2 @@ +## Relevant articles + diff --git a/spring-boot-modules/spring-caching-3/pom.xml b/spring-boot-modules/spring-caching-3/pom.xml new file mode 100644 index 0000000000..dcdf886502 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + spring-caching-3 + 0.1-SNAPSHOT + spring-caching-3 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + + jar + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookRepository.java b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookRepository.java new file mode 100644 index 0000000000..07898aa090 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.caching.disable; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BookRepository extends JpaRepository { + + List findByIsbn(String isbn); +} diff --git a/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReview.java b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReview.java new file mode 100644 index 0000000000..210cdb0d8a --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReview.java @@ -0,0 +1,70 @@ +package com.baeldung.caching.disable; + +import jakarta.persistence.*; + +import java.util.Objects; + +@Entity +@Table(name = "BOOK_REVIEWS") +public class BookReview { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_reviews_reviews_id_seq") + @SequenceGenerator(name = "book_reviews_reviews_id_seq", sequenceName = "book_reviews_reviews_id_seq", allocationSize = 1) + private Long reviewsId; + private String userId; + private String isbn; + private String bookRating; + + public Long getReviewsId() { + return reviewsId; + } + + public void setReviewsId(Long reviewsId) { + this.reviewsId = reviewsId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getBookRating() { + return bookRating; + } + + public void setBookRating(String bookRating) { + this.bookRating = bookRating; + } + + @Override + public String toString() { + return "BookReview{" + "reviewsId=" + reviewsId + ", userId='" + userId + '\'' + ", isbn='" + isbn + '\'' + ", bookRating='" + bookRating + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + BookReview that = (BookReview) o; + return Objects.equals(reviewsId, that.reviewsId) && Objects.equals(userId, that.userId) && Objects.equals(isbn, that.isbn) && Objects.equals(bookRating, that.bookRating); + } + + @Override + public int hashCode() { + return Objects.hash(reviewsId, userId, isbn, bookRating); + } +} diff --git a/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReviewApplication.java b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReviewApplication.java new file mode 100644 index 0000000000..c035424632 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReviewApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.caching.disable; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; + +@SpringBootApplication +@EnableCaching +@EnableAutoConfiguration +public class BookReviewApplication { + public static void main(String[] args) { + SpringApplication.run(BookReviewApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReviewsLogic.java b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReviewsLogic.java new file mode 100644 index 0000000000..1af8cdf4ab --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/BookReviewsLogic.java @@ -0,0 +1,25 @@ +package com.baeldung.caching.disable; + +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +public class BookReviewsLogic { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private CacheManager cacheManager; + + @Cacheable(value = "book_reviews", key = "#isbn") + public List getBooksByIsbn(String isbn) { + return bookRepository.findByIsbn(isbn); + } +} diff --git a/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/CacheConfig.java b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/CacheConfig.java new file mode 100644 index 0000000000..23f90370f5 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/main/java/com/baeldung/caching/disable/CacheConfig.java @@ -0,0 +1,23 @@ +package com.baeldung.caching.disable; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.cache.support.NoOpCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class CacheConfig { + + @Bean + public CacheManager cacheManager(@Value("${appconfig.cache.enabled}") String isCacheEnabled) { + if (isCacheEnabled.equalsIgnoreCase("false")) { + return new NoOpCacheManager(); + } + + return new ConcurrentMapCacheManager(); + } +} diff --git a/spring-boot-modules/spring-caching-3/src/main/resources/application.properties b/spring-boot-modules/spring-caching-3/src/main/resources/application.properties new file mode 100644 index 0000000000..f3c5e31283 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +# Enabling H2 Console +spring.h2.console.enabled=true +spring.h2.console.path=/h2 +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true diff --git a/spring-boot-modules/spring-caching-3/src/test/java/com/baeldung/caching/disable/BookReviewsLogicCacheDisabledUnitTest.java b/spring-boot-modules/spring-caching-3/src/test/java/com/baeldung/caching/disable/BookReviewsLogicCacheDisabledUnitTest.java new file mode 100644 index 0000000000..34f1052363 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/test/java/com/baeldung/caching/disable/BookReviewsLogicCacheDisabledUnitTest.java @@ -0,0 +1,68 @@ +package com.baeldung.caching.disable; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = BookReviewApplication.class) +@ExtendWith(OutputCaptureExtension.class) +@TestPropertySource(properties = { + "appconfig.cache.enabled=false" +}) +public class BookReviewsLogicCacheDisabledUnitTest { + + @Autowired + private BookReviewsLogic bookReviewsLogic; + + @Autowired + private BookRepository bookRepository; + + @Test + public void givenCacheDisabled_whenLogicExecuted2ndTime_thenItQueriesDB(CapturedOutput output){ + BookReview bookReview = insertBookReview(); + + bookReviewsLogic.getBooksByIsbn(bookReview.getIsbn()); + + String target = "Hibernate: select b1_0.reviews_id," + + "b1_0.book_rating,b1_0.isbn,b1_0.user_id " + + "from book_reviews b1_0 " + + "where b1_0.isbn=?"; + + String[] logs = output.toString() + .split("\\r?\\n"); + assertThat(logs).anyMatch(e -> e.contains(target)); + + bookReviewsLogic.getBooksByIsbn(bookReview.getIsbn()); + logs = output.toString() + .split("\\r?\\n"); + + long count = Arrays.stream(logs) + .filter(e -> e.contains(target)) + .count(); + + // count 2 means the select query log from 1st and 2nd execution. + assertEquals(2, count); + } + + private BookReview insertBookReview() { + BookReview bookReview = new BookReview(); + bookReview.setReviewsId(123L); + bookReview.setBookRating("3.2"); + bookReview.setUserId("111"); + bookReview.setIsbn("1234"); + bookRepository.save(bookReview); + return bookReview; + } +} diff --git a/spring-boot-modules/spring-caching-3/src/test/java/com/baeldung/caching/disable/BookReviewsLogicUnitTest.java b/spring-boot-modules/spring-caching-3/src/test/java/com/baeldung/caching/disable/BookReviewsLogicUnitTest.java new file mode 100644 index 0000000000..8b1b2faa49 --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/test/java/com/baeldung/caching/disable/BookReviewsLogicUnitTest.java @@ -0,0 +1,64 @@ +package com.baeldung.caching.disable; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(classes = BookReviewApplication.class) +@ExtendWith(OutputCaptureExtension.class) +public class BookReviewsLogicUnitTest { + + @Autowired + private BookReviewsLogic bookReviewsLogic; + + @Autowired + private BookRepository bookRepository; + + @Test + public void givenCacheEnabled_whenLogicExecuted2ndTime_thenItDoesntQueriesDB(CapturedOutput output){ + BookReview bookReview = insertBookReview(); + + String target = "Hibernate: select b1_0.reviews_id," + + "b1_0.book_rating,b1_0.isbn,b1_0.user_id " + + "from book_reviews b1_0 " + + "where b1_0.isbn=?"; + + // 1st execution + bookReviewsLogic.getBooksByIsbn(bookReview.getIsbn()); + String[] logs = output.toString() + .split("\\r?\\n"); + assertThat(logs).anyMatch(e -> e.contains(target)); + + // 2nd execution + bookReviewsLogic.getBooksByIsbn(bookReview.getIsbn()); + logs = output.toString() + .split("\\r?\\n"); + System.out.println(logs); + long count = Arrays.stream(logs) + .filter(e -> e.equals(target)) + .count(); + + // count 1 means the select query log from 1st execution. + assertEquals(1,count); + } + + private BookReview insertBookReview() { + BookReview bookReview = new BookReview(); + bookReview.setReviewsId(123L); + bookReview.setBookRating("3.2"); + bookReview.setUserId("111"); + bookReview.setIsbn("1234"); + bookRepository.save(bookReview); + return bookReview; + } +} diff --git a/spring-boot-modules/spring-caching-3/src/test/resources/application.properties b/spring-boot-modules/spring-caching-3/src/test/resources/application.properties new file mode 100644 index 0000000000..c62237927f --- /dev/null +++ b/spring-boot-modules/spring-caching-3/src/test/resources/application.properties @@ -0,0 +1,12 @@ +appconfig.cache.enabled=true +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +# Enabling H2 Console +spring.h2.console.enabled=true +spring.h2.console.path=/h2 +spring.jpa.hibernate.ddl-auto=update +server.port=8000 +spring.jpa.show-sql=true \ No newline at end of file