Skip to content

Commit 00093eb

Browse files
authored
refactor: 대학 캐시 무효화 정책 추가 (#660)
* refactor: 대학 캐시 무효화 정책 추가 * test: 대학 캐시 무효화 정책 테스트 추가
1 parent 3a7e3c9 commit 00093eb

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import com.example.solidconnection.admin.university.dto.AdminHostUniversityResponse;
1212
import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition;
1313
import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest;
14+
import com.example.solidconnection.cache.annotation.DefaultCacheOut;
15+
import com.example.solidconnection.cache.manager.CustomCacheManager;
1416
import com.example.solidconnection.common.exception.CustomException;
1517
import com.example.solidconnection.location.country.domain.Country;
1618
import com.example.solidconnection.location.country.repository.CountryRepository;
@@ -19,6 +21,7 @@
1921
import com.example.solidconnection.university.domain.HostUniversity;
2022
import com.example.solidconnection.university.repository.HostUniversityRepository;
2123
import com.example.solidconnection.university.repository.UnivApplyInfoRepository;
24+
import java.util.List;
2225
import lombok.RequiredArgsConstructor;
2326
import org.springframework.data.domain.Page;
2427
import org.springframework.data.domain.Pageable;
@@ -33,6 +36,7 @@ public class AdminHostUniversityService {
3336
private final CountryRepository countryRepository;
3437
private final RegionRepository regionRepository;
3538
private final UnivApplyInfoRepository univApplyInfoRepository;
39+
private final CustomCacheManager cacheManager;
3640

3741
@Transactional(readOnly = true)
3842
public Page<AdminHostUniversityResponse> getHostUniversities(
@@ -56,6 +60,11 @@ public AdminHostUniversityDetailResponse getHostUniversity(Long id) {
5660
}
5761

5862
@Transactional
63+
@DefaultCacheOut(
64+
key = {"univApplyInfoTextSearch", "university:recommend:general"},
65+
cacheManager = "customCacheManager",
66+
prefix = true
67+
)
5968
public AdminHostUniversityDetailResponse createHostUniversity(AdminHostUniversityCreateRequest request) {
6069
validateKoreanNameNotExists(request.koreanName());
6170

@@ -89,6 +98,11 @@ private void validateKoreanNameNotExists(String koreanName) {
8998
}
9099

91100
@Transactional
101+
@DefaultCacheOut(
102+
key = {"univApplyInfoTextSearch", "university:recommend:general"},
103+
cacheManager = "customCacheManager",
104+
prefix = true
105+
)
92106
public AdminHostUniversityDetailResponse updateHostUniversity(Long id, AdminHostUniversityUpdateRequest request) {
93107
HostUniversity hostUniversity = hostUniversityRepository.findById(id)
94108
.orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND));
@@ -112,6 +126,8 @@ public AdminHostUniversityDetailResponse updateHostUniversity(Long id, AdminHost
112126
region
113127
);
114128

129+
evictUnivApplyInfoDetailCaches(id);
130+
115131
return AdminHostUniversityDetailResponse.from(hostUniversity);
116132
}
117133

@@ -135,6 +151,11 @@ private Region findRegionByCode(String regionCode) {
135151
}
136152

137153
@Transactional
154+
@DefaultCacheOut(
155+
key = {"univApplyInfoTextSearch", "university:recommend:general"},
156+
cacheManager = "customCacheManager",
157+
prefix = true
158+
)
138159
public void deleteHostUniversity(Long id) {
139160
HostUniversity hostUniversity = hostUniversityRepository.findById(id)
140161
.orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND));
@@ -149,4 +170,14 @@ private void validateNoReferences(Long hostUniversityId) {
149170
throw new CustomException(HOST_UNIVERSITY_HAS_REFERENCES);
150171
}
151172
}
173+
174+
private void evictUnivApplyInfoDetailCaches(Long hostUniversityId) {
175+
List<Long> affectedUnivApplyInfoIds = univApplyInfoRepository.findIdsByUniversityId(hostUniversityId);
176+
177+
List<String> cacheKeys = affectedUnivApplyInfoIds.stream()
178+
.map(univApplyInfoId -> "univApplyInfo:" + univApplyInfoId)
179+
.toList();
180+
181+
cacheManager.evictMultiple(cacheKeys);
182+
}
152183
}

src/main/java/com/example/solidconnection/cache/manager/CustomCacheManager.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.example.solidconnection.cache.manager;
22

33
import java.time.Duration;
4+
import java.util.List;
45
import java.util.Set;
56
import org.springframework.beans.factory.annotation.Autowired;
67
import org.springframework.data.redis.core.RedisTemplate;
@@ -38,4 +39,10 @@ public void evictUsingPrefix(String key) {
3839
redisTemplate.delete(keys);
3940
}
4041
}
42+
43+
public void evictMultiple(List<String> keys) {
44+
if (keys != null && !keys.isEmpty()) {
45+
redisTemplate.delete(keys);
46+
}
47+
}
4148
}

src/main/java/com/example/solidconnection/university/repository/UnivApplyInfoRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,11 @@ default UnivApplyInfo getUnivApplyInfoById(Long id) {
6868
List<UnivApplyInfo> findAllByIds(@Param("ids") List<Long> ids);
6969

7070
boolean existsByUniversityId(Long universityId);
71+
72+
@Query("""
73+
SELECT uai.id
74+
FROM UnivApplyInfo uai
75+
WHERE uai.university.id = :universityId
76+
""")
77+
List<Long> findIdsByUniversityId(@Param("universityId") Long universityId);
7178
}

src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.assertj.core.api.Assertions.assertThatCode;
5+
import static org.mockito.BDDMockito.then;
6+
import static org.mockito.Mockito.times;
57

68
import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest;
79
import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse;
810
import com.example.solidconnection.admin.university.dto.AdminHostUniversityResponse;
911
import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition;
1012
import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest;
1113
import com.example.solidconnection.admin.university.service.AdminHostUniversityService;
14+
import com.example.solidconnection.cache.manager.CustomCacheManager;
1215
import com.example.solidconnection.common.exception.CustomException;
1316
import com.example.solidconnection.common.exception.ErrorCode;
1417
import com.example.solidconnection.location.country.domain.Country;
@@ -17,13 +20,16 @@
1720
import com.example.solidconnection.location.region.fixture.RegionFixture;
1821
import com.example.solidconnection.support.TestContainerSpringBootTest;
1922
import com.example.solidconnection.university.domain.HostUniversity;
23+
import com.example.solidconnection.university.domain.UnivApplyInfo;
2024
import com.example.solidconnection.university.fixture.UnivApplyInfoFixtureBuilder;
2125
import com.example.solidconnection.university.fixture.UniversityFixture;
2226
import com.example.solidconnection.university.repository.HostUniversityRepository;
27+
import java.util.List;
2328
import org.junit.jupiter.api.DisplayName;
2429
import org.junit.jupiter.api.Nested;
2530
import org.junit.jupiter.api.Test;
2631
import org.springframework.beans.factory.annotation.Autowired;
32+
import org.springframework.boot.test.mock.mockito.SpyBean;
2733
import org.springframework.data.domain.Page;
2834
import org.springframework.data.domain.PageRequest;
2935

@@ -49,6 +55,9 @@ class AdminHostUniversityServiceTest {
4955
@Autowired
5056
private UnivApplyInfoFixtureBuilder univApplyInfoFixtureBuilder;
5157

58+
@SpyBean
59+
private CustomCacheManager cacheManager;
60+
5261
@Nested
5362
class 목록_조회 {
5463

@@ -398,4 +407,82 @@ class 삭제 {
398407
.hasMessage(ErrorCode.HOST_UNIVERSITY_HAS_REFERENCES.getMessage());
399408
}
400409
}
410+
411+
@Nested
412+
class 캐시_무효화 {
413+
414+
@Test
415+
void 대학_생성_시_캐시가_무효화된다() {
416+
// given
417+
Country country = countryFixture.미국();
418+
Region region = regionFixture.영미권();
419+
420+
AdminHostUniversityCreateRequest request = new AdminHostUniversityCreateRequest(
421+
"캐시 테스트 대학",
422+
"Cache Test University",
423+
"캐시 테스트 대학",
424+
"https://homepage.com",
425+
null, null,
426+
"https://logo.com/image.png",
427+
"https://background.com/image.png",
428+
null,
429+
country.getCode(),
430+
region.getCode()
431+
);
432+
433+
// when
434+
adminHostUniversityService.createHostUniversity(request);
435+
436+
// then
437+
then(cacheManager).should(times(1)).evictUsingPrefix("univApplyInfoTextSearch");
438+
then(cacheManager).should(times(1)).evictUsingPrefix("university:recommend:general");
439+
}
440+
441+
@Test
442+
void 대학_수정_시_캐시가_무효화된다() {
443+
// given
444+
HostUniversity university = universityFixture.괌_대학();
445+
UnivApplyInfo univApplyInfo = univApplyInfoFixtureBuilder.univApplyInfo()
446+
.termId(1L)
447+
.koreanName("괌 대학 지원 정보")
448+
.university(university)
449+
.create();
450+
451+
Country country = countryFixture.일본();
452+
Region region = regionFixture.아시아();
453+
454+
AdminHostUniversityUpdateRequest request = new AdminHostUniversityUpdateRequest(
455+
"수정된 대학명",
456+
"Updated University",
457+
"수정된 표시명",
458+
null, null, null,
459+
"https://logo.com/image.png",
460+
"https://background.com/image.png",
461+
null,
462+
country.getCode(),
463+
region.getCode()
464+
);
465+
466+
// when
467+
adminHostUniversityService.updateHostUniversity(university.getId(), request);
468+
469+
// then
470+
then(cacheManager).should(times(1)).evictUsingPrefix("univApplyInfoTextSearch");
471+
then(cacheManager).should(times(1)).evictUsingPrefix("university:recommend:general");
472+
then(cacheManager).should(times(1)).evictMultiple(List.of("univApplyInfo:" + univApplyInfo.getId()));
473+
}
474+
475+
@Test
476+
void 대학_삭제_시_캐시가_무효화된다() {
477+
// given
478+
HostUniversity university = universityFixture.괌_대학();
479+
480+
// when
481+
adminHostUniversityService.deleteHostUniversity(university.getId());
482+
483+
// then
484+
then(cacheManager).should(times(1)).evictUsingPrefix("univApplyInfoTextSearch");
485+
then(cacheManager).should(times(1)).evictUsingPrefix("university:recommend:general");
486+
}
487+
}
401488
}

0 commit comments

Comments
 (0)