diff --git a/Account-Service/pom.xml b/Account-Service/pom.xml
index 3d4401c..25152a7 100644
--- a/Account-Service/pom.xml
+++ b/Account-Service/pom.xml
@@ -42,6 +42,14 @@
org.springframework.cloud
spring-cloud-starter-openfeign
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+
org.springframework.boot
@@ -64,6 +72,11 @@
spring-boot-starter-test
test
+
+ com.h2database
+ h2
+ runtime
+
diff --git a/Account-Service/src/main/java/org/training/account/service/AccountServiceApplication.java b/Account-Service/src/main/java/org/training/account/service/AccountServiceApplication.java
index 1949174..151beac 100644
--- a/Account-Service/src/main/java/org/training/account/service/AccountServiceApplication.java
+++ b/Account-Service/src/main/java/org/training/account/service/AccountServiceApplication.java
@@ -2,10 +2,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
+@EnableCaching
public class AccountServiceApplication {
public static void main(String[] args) {
diff --git a/Account-Service/src/main/java/org/training/account/service/external/TransactionService.java b/Account-Service/src/main/java/org/training/account/service/external/TransactionService.java
index 497582b..0b00281 100644
--- a/Account-Service/src/main/java/org/training/account/service/external/TransactionService.java
+++ b/Account-Service/src/main/java/org/training/account/service/external/TransactionService.java
@@ -8,7 +8,7 @@
import java.util.List;
-@FeignClient(name = "transaction-service", configuration = FeignConfiguration.class)
+@FeignClient(name = "transaction-service", url = "http://localhost:8082", configuration = FeignConfiguration.class)
public interface TransactionService {
/**
diff --git a/Account-Service/src/main/java/org/training/account/service/service/implementation/AccountServiceImpl.java b/Account-Service/src/main/java/org/training/account/service/service/implementation/AccountServiceImpl.java
index 13728fb..486761c 100644
--- a/Account-Service/src/main/java/org/training/account/service/service/implementation/AccountServiceImpl.java
+++ b/Account-Service/src/main/java/org/training/account/service/service/implementation/AccountServiceImpl.java
@@ -4,6 +4,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.training.account.service.exception.*;
@@ -162,6 +163,7 @@ public String getBalance(String accountNumber) {
* @return A list of transaction responses
*/
@Override
+ @Cacheable(value = "transactions", key = "#accountId")
public List getTransactionsFromAccountId(String accountId) {
return transactionService.getTransactionsFromAccountId(accountId);
@@ -213,4 +215,4 @@ public AccountDto readAccountByUserId(Long userId) {
return accountDto;
}).orElseThrow(ResourceNotFound::new);
}
-}
\ No newline at end of file
+}
diff --git a/Account-Service/src/main/resources/application.yml b/Account-Service/src/main/resources/application.yml
index 094aca9..208a4a9 100644
--- a/Account-Service/src/main/resources/application.yml
+++ b/Account-Service/src/main/resources/application.yml
@@ -7,17 +7,30 @@ spring:
not_found: 404
datasource:
- url: jdbc:mysql://localhost:3306/account_service
- username: root
- password: root
+ url: jdbc:h2:mem:testdb
+ driver-class-name: org.h2.Driver
+ username: sa
+ password: password
jpa:
+ database-platform: org.hibernate.dialect.H2Dialect
hibernate:
- ddl-auto: update
- show-sql: true
- properties:
- hibernate:
- format_sql: true
+ ddl-auto: create-drop
+ show-sql: false
+
+ cache:
+ type: caffeine
+ caffeine:
+ spec: maximumSize=1000,expireAfterWrite=5m
+ cache-names:
+ - transactions
server:
port: 8081
+
+# Direct URL configuration for Feign clients
+feign:
+ client:
+ config:
+ transaction-service:
+ url: http://localhost:8082
diff --git a/Account-Service/src/test/java/org/training/account/service/CachePerformanceTest.java b/Account-Service/src/test/java/org/training/account/service/CachePerformanceTest.java
new file mode 100644
index 0000000..e283588
--- /dev/null
+++ b/Account-Service/src/test/java/org/training/account/service/CachePerformanceTest.java
@@ -0,0 +1,91 @@
+package org.training.account.service;
+
+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 org.springframework.test.context.ActiveProfiles;
+import org.training.account.service.external.TransactionService;
+import org.training.account.service.model.dto.external.TransactionResponse;
+import org.training.account.service.service.AccountService;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+@ActiveProfiles("test")
+public class CachePerformanceTest {
+
+ @Autowired
+ private AccountService accountService;
+
+ @MockBean
+ private TransactionService transactionService;
+
+ @Test
+ public void testTransactionCachePerformance() {
+ String testAccountId = "TEST_ACCOUNT_001";
+
+ List mockTransactions = Arrays.asList(
+ TransactionResponse.builder()
+ .referenceId("TXN001")
+ .accountId(testAccountId)
+ .transactionType("DEPOSIT")
+ .amount(BigDecimal.valueOf(1000))
+ .localDateTime(LocalDateTime.now())
+ .transactionStatus("COMPLETED")
+ .comments("Test transaction")
+ .build()
+ );
+
+ when(transactionService.getTransactionsFromAccountId(anyString()))
+ .thenAnswer(invocation -> {
+ Thread.sleep(100);
+ return mockTransactions;
+ });
+
+ System.out.println("=== Cache Performance Test ===");
+
+ long startTime1 = System.currentTimeMillis();
+ List transactions1 = accountService.getTransactionsFromAccountId(testAccountId);
+ long endTime1 = System.currentTimeMillis();
+ long firstCallTime = endTime1 - startTime1;
+
+ System.out.println("First call (cache miss): " + firstCallTime + "ms");
+ System.out.println("Transactions found: " + (transactions1 != null ? transactions1.size() : 0));
+
+ long startTime2 = System.currentTimeMillis();
+ List transactions2 = accountService.getTransactionsFromAccountId(testAccountId);
+ long endTime2 = System.currentTimeMillis();
+ long secondCallTime = endTime2 - startTime2;
+
+ System.out.println("Second call (cache hit): " + secondCallTime + "ms");
+ System.out.println("Transactions found: " + (transactions2 != null ? transactions2.size() : 0));
+
+ if (firstCallTime > 0) {
+ double improvement = ((double)(firstCallTime - secondCallTime) / firstCallTime) * 100;
+ System.out.println("Performance improvement: " + String.format("%.1f", improvement) + "%");
+
+ if (improvement > 90) {
+ System.out.println("✅ Cache performance target achieved (>90% improvement)");
+ } else if (improvement > 50) {
+ System.out.println("⚠️ Cache working but improvement below target (<90%)");
+ } else {
+ System.out.println("❌ Cache may not be working effectively");
+ }
+ }
+
+ long startTime3 = System.currentTimeMillis();
+ List transactions3 = accountService.getTransactionsFromAccountId(testAccountId);
+ long endTime3 = System.currentTimeMillis();
+ long thirdCallTime = endTime3 - startTime3;
+
+ System.out.println("Third call (cache hit): " + thirdCallTime + "ms");
+ System.out.println("=== Test Complete ===");
+ }
+}
diff --git a/Account-Service/src/test/resources/application-test.yml b/Account-Service/src/test/resources/application-test.yml
new file mode 100644
index 0000000..0b86dc2
--- /dev/null
+++ b/Account-Service/src/test/resources/application-test.yml
@@ -0,0 +1,39 @@
+spring:
+ application:
+ name: account-service-test
+ ok: 200
+ not_found: 404
+ bad_request: 400
+ conflict: 409
+
+ datasource:
+ url: jdbc:h2:mem:testdb
+ driver-class-name: org.h2.Driver
+ username: sa
+ password: password
+
+ jpa:
+ database-platform: org.hibernate.dialect.H2Dialect
+ hibernate:
+ ddl-auto: create-drop
+ show-sql: false
+
+ cache:
+ type: caffeine
+ caffeine:
+ spec: maximumSize=100,expireAfterWrite=1m
+ cache-names:
+ - transactions
+
+# Mock external services for testing
+feign:
+ client:
+ config:
+ default:
+ connectTimeout: 5000
+ readTimeout: 5000
+
+logging:
+ level:
+ org.training.account.service: DEBUG
+ org.springframework.cache: DEBUG
diff --git a/test-cache-performance.sh b/test-cache-performance.sh
new file mode 100755
index 0000000..a7255f0
--- /dev/null
+++ b/test-cache-performance.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+echo "=== Cache Performance Testing Script ==="
+echo "This script will test the cache implementation by making HTTP requests"
+echo
+
+ACCOUNT_ID="ACC0000001"
+BASE_URL="http://localhost:8081"
+ENDPOINT="/accounts/${ACCOUNT_ID}/transactions"
+
+echo "Testing endpoint: ${BASE_URL}${ENDPOINT}"
+echo
+
+make_request() {
+ local request_num=$1
+ echo "Request #${request_num}:"
+
+ start_time=$(date +%s%3N)
+ response=$(curl -s -w "%{http_code}" -o /tmp/response_${request_num}.json "${BASE_URL}${ENDPOINT}")
+ end_time=$(date +%s%3N)
+
+ duration=$((end_time - start_time))
+
+ if [ "$response" = "200" ]; then
+ transaction_count=$(cat /tmp/response_${request_num}.json | jq '. | length' 2>/dev/null || echo "unknown")
+ echo " ✅ Success (${duration}ms) - Transactions: ${transaction_count}"
+ else
+ echo " ❌ Failed (HTTP ${response}) - Time: ${duration}ms"
+ fi
+
+ echo " Response time: ${duration}ms"
+ return $duration
+}
+
+echo "Making 5 consecutive requests to test cache performance..."
+echo
+
+times=()
+for i in {1..5}; do
+ make_request $i
+ times+=($?)
+ echo
+ sleep 1
+done
+
+echo "=== Performance Analysis ==="
+echo "Request times: ${times[@]}ms"
+
+if [ ${#times[@]} -ge 2 ]; then
+ first_time=${times[0]}
+ second_time=${times[1]}
+
+ if [ $first_time -gt 0 ]; then
+ improvement=$(( (first_time - second_time) * 100 / first_time ))
+ echo "Performance improvement from 1st to 2nd request: ${improvement}%"
+
+ if [ $improvement -gt 90 ]; then
+ echo "✅ Cache performance target achieved (>90% improvement)"
+ elif [ $improvement -gt 50 ]; then
+ echo "⚠️ Cache working but improvement below target"
+ else
+ echo "❌ Cache may not be working effectively"
+ fi
+ fi
+fi
+
+echo
+echo "=== Test Complete ==="