Skip to content

Commit 6087d92

Browse files
committed
refactor: 다이어리 쓰기 이벤트 발생 시 지역 count 반영 및 관련 캐시(evict) 처리
1 parent b85d238 commit 6087d92

File tree

7 files changed

+131
-47
lines changed

7 files changed

+131
-47
lines changed

src/main/java/com/example/log4u/domain/diary/facade/DiaryFacade.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,9 @@ public class DiaryFacade {
3838

3939
/**
4040
* 다이어리 생성 use case
41-
* <ul><li>호출 과정</li></ul>
42-
* 1. mediaService: 섬네일 이미지 url 생성<br>
43-
* 2. diaryService: 다이어리 생성<br>
44-
* 2. mediaService: 해당 다이어리의 이미지 저장<br>
41+
* 1. mediaService: 섬네일 이미지 url 생성
42+
* 2. diaryService: 다이어리 생성
43+
* 2. mediaService: 해당 다이어리의 이미지 저장
4544
* 3. mapService: 해당 구역 카운트 증가
4645
* 4. diaryGeohashService: 해당 다이어리 위치가 포함되어있는 geoHash 문자열 저장
4746
* */
@@ -60,30 +59,29 @@ public void createDiary(Long userId, DiaryRequestDto request) {
6059

6160
/**
6261
* 다이어리 삭제 use case
63-
* <ul><li>호출 과정</li></ul>
6462
* 1. diaryService: 다이어리 검증
65-
* 2. mediaService: 해당 다이어리 이미지 삭제<br>
66-
* 3. mapService: 해당 구역 카운트 감소
67-
* 4. diaryGeohashService: 캐싱 되어있는 id, 데이터 삭제
68-
* 5. diaryService: 다이어리 삭제<br>
69-
*
63+
* 2. mediaService: 해당 다이어리 이미지 삭제
64+
* 3. mapService: 시/도, 시/군/구 지역 다이어리 개수 감소 및 클러스터 캐싱 키 삭제
65+
* 4. diaryGeohashService: 다이어리 Goehash 문자열 및 마커 캐싱 키 삭제
66+
* 5. diaryService: 다이어리 삭제
7067
* */
7168
@Transactional
7269
public void deleteDiary(Long userId, Long diaryId) {
7370
Diary diary = diaryService.getDiaryAfterValidateOwnership(diaryId, userId);
7471
mediaService.deleteMediaByDiaryId(diaryId);
7572
hashtagService.deleteHashtagsByDiaryId(diaryId);
76-
mapService.decreaseRegionDiaryCount(diary.getLocation().getLatitude(), diary.getLocation().getLongitude());
7773

78-
diaryGeohashService.deleteGeohashAndCache(diaryId);
74+
double lat = diary.getLocation().getLatitude();
75+
double lon = diary.getLocation().getLongitude();
76+
mapService.decreaseRegionDiaryCount(lat, lon);
77+
diaryGeohashService.deleteGeohash(diaryId);
7978
diaryService.deleteDiary(diary);
8079
}
8180

8281
/**
8382
* 다이어리 수정 use case
84-
* <ul><li>호출 과정</li></ul>
85-
* 1. diaryService: 다이어리 검증<br>
86-
* 2. mediaService: 해당 다이어리 이미지 삭제<br>
83+
* 1. diaryService: 다이어리 검증
84+
* 2. mediaService: 해당 다이어리 이미지 삭제
8785
* 3. diaryService: 다이어리 수정
8886
* 4. mapService: 해당 구역 카운트 감소
8987
* 5. mapService: 해당 구역 카운트 증가
@@ -93,10 +91,13 @@ public void updateDiary(Long userId, Long diaryId, DiaryRequestDto request) {
9391
Diary diary = diaryService.getDiaryAfterValidateOwnership(diaryId, userId);
9492
mediaService.updateMediaByDiaryId(diary.getDiaryId(), request.mediaList());
9593
hashtagService.saveOrUpdateHashtag(diary.getDiaryId(), request.hashtagList());
96-
mapService.decreaseRegionDiaryCount(diary.getLocation().getLatitude(), diary.getLocation().getLongitude());
97-
mapService.increaseRegionDiaryCount(request.location().latitude(), request.location().longitude());
98-
9994
String newThumbnailUrl = mediaService.extractThumbnailUrl(request.mediaList());
95+
96+
double oldLat = diary.getLocation().getLatitude();
97+
double oldLon = diary.getLocation().getLongitude();
98+
double newLat = request.location().latitude();
99+
double newLon = request.location().longitude();
100+
mapService.updateRegionDiaryCount(oldLat, oldLon, newLat, newLon);
100101
diaryService.updateDiary(diary, request, newThumbnailUrl);
101102
}
102103

src/main/java/com/example/log4u/domain/diary/repository/DiaryGeoHashRepository.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,14 @@ public interface DiaryGeoHashRepository extends JpaRepository<DiaryGeoHash, Long
1515
List<Long> findDiaryIdByGeohash(@Param("geohash") String geohash);
1616

1717
DiaryGeoHash findByDiaryId(Long diaryId);
18+
19+
@Query(value = """
20+
SELECT g.*
21+
FROM diarygeohash g
22+
JOIN diary d ON d.diaryId = g.diaryId
23+
WHERE d.latitude = :lat
24+
AND d.longitude = :lon
25+
""",
26+
nativeQuery = true)
27+
DiaryGeoHash findByLatLon(@Param("lat") double lat, @Param("lon") double lon);
1828
}

src/main/java/com/example/log4u/domain/diary/service/DiaryGeohashService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public void saveGeohash(Long diaryId, double lat, double lon) {
3232
}
3333

3434
@Transactional
35-
public void deleteGeohashAndCache(Long diaryId) {
35+
public void deleteGeohash(Long diaryId) {
3636
DiaryGeoHash geoHash = diaryGeoHashRepository.findByDiaryId(diaryId);
3737
markerCacheDao.evict(geoHash.getGeohash());
3838
diaryGeoHashRepository.deleteById(diaryId);
@@ -41,4 +41,8 @@ public void deleteGeohashAndCache(Long diaryId) {
4141
public List<Long> getDiaryIdsByGeohash(String geohash) {
4242
return diaryGeoHashRepository.findDiaryIdByGeohash(geohash);
4343
}
44+
45+
public DiaryGeoHash getGeohashByLatLon(double lat, double lon) {
46+
return diaryGeoHashRepository.findByLatLon(lat, lon);
47+
}
4448
}

src/main/java/com/example/log4u/domain/map/repository/sido/SidoAreasRepository.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,23 @@ WHERE ST_Contains(s.geom, ST_SetSRID(ST_Point(:lon, :lat), 4326)) = true
2828
List<SidoAreas> findWithinBoundingBox(@Param("south") double south, @Param("north") double north,
2929
@Param("west") double west, @Param("east") double east
3030
);
31+
32+
33+
@Query("""
34+
SELECT s FROM SidoAreas s
35+
WHERE ST_Contains(s.geom, ST_SetSRID(ST_Point(:lon, :lat), 4326)) = true
36+
""")
37+
SidoAreas findSidoAreasByLatLon(@Param("lat") Double lat, @Param("lon") Double lon);
38+
39+
@Query("""
40+
SELECT CASE WHEN COUNT(sOld) > 0 THEN true ELSE false END
41+
FROM SidoAreas sOld, SidoAreas sNew
42+
WHERE ST_Contains(sOld.geom, ST_SetSRID(ST_Point(:oldLon, :oldLat), 4326)) = true
43+
AND ST_Contains(sNew.geom, ST_SetSRID(ST_Point(:newLon, :newLat), 4326)) = true
44+
AND sOld.id = sNew.id
45+
""")
46+
boolean isSameSidoRegion(@Param("oldLat") Double oldLat,
47+
@Param("oldLon") Double oldLon,
48+
@Param("newLat") Double newLat,
49+
@Param("newLon") Double newLon);
3150
}

src/main/java/com/example/log4u/domain/map/repository/sigg/SiggAreasRepository.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,22 @@ List<SiggAreas> findWithinBoundingBox(@Param("south") double south, @Param("nort
2929
@Param("west") double west, @Param("east") double east
3030
);
3131

32+
@Query("""
33+
SELECT r FROM SiggAreas r
34+
WHERE ST_Contains(r.geom, ST_SetSRID(ST_Point(:lon, :lat), 4326)) = true
35+
""")
36+
SiggAreas findSiggAreasByLatLon(@Param("lat") Double lat, @Param("lon") Double lon);
37+
38+
@Query("""
39+
SELECT CASE WHEN COUNT(r1) > 0 THEN true ELSE false END
40+
FROM SiggAreas r1, SiggAreas r2
41+
WHERE ST_Contains(r1.geom, ST_SetSRID(ST_Point(:oldLon, :oldLat), 4326)) = true
42+
AND ST_Contains(r2.geom, ST_SetSRID(ST_Point(:newLon, :newLat), 4326)) = true
43+
AND r1.gid = r2.gid
44+
""")
45+
boolean isSameSiggRegion(@Param("oldLat") Double oldLat,
46+
@Param("oldLon") Double oldLon,
47+
@Param("newLat") Double newLat,
48+
@Param("newLon") Double newLon);
49+
3250
}

src/main/java/com/example/log4u/domain/map/service/MapService.java

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
import org.springframework.stereotype.Service;
66
import org.springframework.transaction.annotation.Transactional;
77

8+
import com.example.log4u.domain.diary.entity.DiaryGeoHash;
9+
import com.example.log4u.domain.diary.service.DiaryGeohashService;
810
import com.example.log4u.domain.map.cache.dao.ClusterCacheDao;
911
import com.example.log4u.domain.map.cache.dao.MarkerCacheDao;
1012
import com.example.log4u.domain.map.dto.response.DiaryClusterResponseDto;
1113
import com.example.log4u.domain.map.dto.response.DiaryMarkerResponseDto;
14+
import com.example.log4u.domain.map.entity.SidoAreas;
15+
import com.example.log4u.domain.map.entity.SiggAreas;
1216
import com.example.log4u.domain.map.exception.InvalidGeohashException;
1317
import com.example.log4u.domain.map.repository.sido.SidoAreasDiaryCountRepository;
1418
import com.example.log4u.domain.map.repository.sido.SidoAreasRepository;
@@ -29,6 +33,7 @@ public class MapService {
2933
private final SiggAreasDiaryCountRepository siggAreasDiaryCountRepository;
3034
private final MarkerCacheDao markerCacheDao;
3135
private final ClusterCacheDao clusterCacheDao;
36+
private final DiaryGeohashService diaryGeohashService;
3237

3338
/**
3439
* 캐싱 전략: Look-Aside + Write-Around
@@ -63,43 +68,70 @@ public List<DiaryMarkerResponseDto> getDiaryMarkers(String geohash) {
6368
return markers;
6469
}
6570

66-
private void validateGeohashLength(String geohash, int expectedLength) {
67-
if (geohash == null || geohash.length() != expectedLength) {
68-
throw new InvalidGeohashException();
69-
}
70-
}
71-
7271
@Transactional
7372
public void increaseRegionDiaryCount(Double lat, Double lon) {
74-
sidoAreasRepository.findRegionByLatLon(lat, lon)
75-
.flatMap(sido -> sidoAreasDiaryCountRepository.findById(sido.getId()))
76-
.ifPresent(count -> {
77-
count.incrementCount();
78-
sidoAreasDiaryCountRepository.save(count);
79-
});
80-
81-
siggAreasRepository.findRegionByLatLon(lat, lon)
82-
.flatMap(sigg -> siggAreasDiaryCountRepository.findById(sigg.getGid()))
83-
.ifPresent(count -> {
84-
count.incrementCount();
85-
siggAreasDiaryCountRepository.save(count);
86-
});
73+
SidoAreas sido = updateSidoCount(lat, lon, +1);
74+
SiggAreas sigg = updateSiggCount(lat, lon, +1);
75+
clusterCacheDao.evictSido(sido.getGeohash());
76+
clusterCacheDao.evictSigg(sigg.getGeohash());
8777
}
8878

8979
@Transactional
9080
public void decreaseRegionDiaryCount(Double lat, Double lon) {
91-
sidoAreasRepository.findRegionByLatLon(lat, lon)
92-
.flatMap(sido -> sidoAreasDiaryCountRepository.findById(sido.getId()))
81+
SidoAreas sido = updateSidoCount(lat, lon, -1);
82+
SiggAreas sigg = updateSiggCount(lat, lon, -1);
83+
clusterCacheDao.evictSido(sido.getGeohash());
84+
clusterCacheDao.evictSigg(sigg.getGeohash());
85+
}
86+
87+
@Transactional
88+
public void updateRegionDiaryCount(double oldLat, double oldLon, double newLat, double newLon) {
89+
boolean sameSido = sidoAreasRepository.isSameSidoRegion(oldLat, oldLon, newLat, newLon);
90+
boolean sameSigg = siggAreasRepository.isSameSiggRegion(oldLat, oldLon, newLat, newLon);
91+
92+
if (!sameSido) {
93+
updateSidoCount(oldLat, oldLon, -1);
94+
updateSidoCount(newLat, newLon, +1);
95+
}
96+
97+
if (!sameSigg) {
98+
updateSiggCount(oldLat, oldLon, -1);
99+
updateSiggCount(newLat, newLon, +1);
100+
}
101+
102+
DiaryGeoHash diaryGeoHash = diaryGeohashService.getGeohashByLatLon(oldLat, oldLon);
103+
markerCacheDao.evict(diaryGeoHash.getGeohash());
104+
}
105+
106+
private SidoAreas updateSidoCount(Double lat, Double lon, int delta) {
107+
SidoAreas sido = sidoAreasRepository.findSidoAreasByLatLon(lat, lon);
108+
sidoAreasDiaryCountRepository.findById(sido.getId())
93109
.ifPresent(count -> {
94-
count.decrementCount();
95-
sidoAreasDiaryCountRepository.save(count);
110+
if (delta > 0) {
111+
count.incrementCount();
112+
} else if (delta < 0) {
113+
count.decrementCount();
114+
}
96115
});
116+
return sido;
117+
}
97118

98-
siggAreasRepository.findRegionByLatLon(lat, lon)
99-
.flatMap(sigg -> siggAreasDiaryCountRepository.findById(sigg.getGid()))
119+
private SiggAreas updateSiggCount(Double lat, Double lon, int delta) {
120+
SiggAreas sigg = siggAreasRepository.findSiggAreasByLatLon(lat, lon);
121+
siggAreasDiaryCountRepository.findById(sigg.getGid())
100122
.ifPresent(count -> {
101-
count.decrementCount();
102-
siggAreasDiaryCountRepository.save(count);
123+
if (delta > 0) {
124+
count.incrementCount();
125+
} else if (delta < 0) {
126+
count.decrementCount();
127+
}
103128
});
129+
return sigg;
130+
}
131+
132+
private void validateGeohashLength(String geohash, int expectedLength) {
133+
if (geohash == null || geohash.length() != expectedLength) {
134+
throw new InvalidGeohashException();
135+
}
104136
}
105137
}

src/test/java/com/example/log4u/domain/diary/facade/DiaryFacadeTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void deleteDiary() {
114114
diary.getLocation().getLatitude(),
115115
diary.getLocation().getLongitude()
116116
);
117-
verify(diaryGeohashService).deleteGeohashAndCache(diaryId);
117+
verify(diaryGeohashService).deleteGeohash(diaryId);
118118
verify(diaryService).deleteDiary(diary);
119119
}
120120

0 commit comments

Comments
 (0)