Post
신규 웹 프로젝트 - 3 (캐싱)
Spring Boot에서 공통 코드 테이블 캐싱 처리하기
프로젝트에서 공통 코드를 매번 DB에서 조회하지 않고, 서버 기동 시 캐싱해서 사용하는 구조로 개선했습니다. Vue 3와 Spring Boot(Java 1.8) 환경에서 적용한 방식이며, 등록/수정/삭제 시에는 자동으로 캐시를 갱신하도록 구성했습니다.
왜 캐싱을 도입했나?
공통 코드는 자주 변경되지 않으며, 다양한 화면에서 반복적으로 조회됩니다. 매번 DB에 접근하면 다음과 같은 문제가 있습니다:
- 불필요한 쿼리 트래픽 증가
- 응답 속도 저하
- 다수의 화면에서 동일 데이터를 중복 조회
따라서 서버 구동 시 한 번만 로딩하고, 메모리에서 사용하는 방식으로 최적화했습니다.
캐시 구조 설계
Map<String /* GRCODE_CD */, List<Code>> codeCache;
- GRCODE_CD 기준으로 그룹핑
- List<Code>에는 해당 그룹 코드 목록 저장
- CodeCacheService 라는 별도 클래스에서 캐시 관리
구현 방식 요약
1. CodeCacheService 클래스 생성
@Service public class CodeCacheService {
@Autowired private CodeMapper codeMapper;
private final Map<String, List<Code>> codeCache = new ConcurrentHashMap<>();
@PostConstruct public void init() { refreshAll(); }
public List<Code> getCodesByGroup(String grcodeCd) { return codeCache.getOrDefault(grcodeCd, Collections.emptyList()); }
public void refreshAll() { List<Code> allCodes = codeMapper.selectAllCodes(); Map<String, List<Code>> grouped = allCodes.stream() .filter(code -> “Y”.equalsIgnoreCase(code.getUseYn())) .collect(Collectors.groupingBy(Code::getGrcodeCd)); codeCache.clear(); codeCache.putAll(grouped); }
public void refreshGroup(String grcodeCd, String enterCd) { Map<String, Object> param = new HashMap<>(); param.put(“grcodeCd”, grcodeCd); param.put(“enterCd”, enterCd); List<Code> codes = codeMapper.getCodeList(param); codeCache.put(grcodeCd, codes); } }
2. 컨트롤러 수정 (조회 \& 캐시 갱신)
/code/list 캐시에서 조회 @GetMapping(“/list”) public ResponseEntity<List<Code>> getCodeList(@AuthenticationPrincipal CustomUserDetails currentUser, @RequestParam String grcodeCd) { List<Code> list = codeCacheService.getCodesByGroup(grcodeCd); return ResponseEntity.ok(list); }
/code/list 캐시에서 조회 codeCacheService.refreshGroup(code.getGrcodeCd(), code.getEnterCd());
삭제의 경우: deleteList.stream() .map(item -> item.get(“grcodeCd”)) .distinct() .forEach(grcode -> codeCacheService.refreshGroup(grcode, enterCd));
3. 전체 캐시 강제 갱신 API 추가
@GetMapping(“/cache/refreshAll”) public ResponseEntity<String> refreshAllCodes() { codeCacheService.refreshAll(); return ResponseEntity.ok(“전체 코드 캐시 갱신 완료”); }
결과
- 자주 조회되는 공통 코드 캐싱으로 전체 성능 개선
- 등록/수정/삭제 시 캐시 자동 동기화
- 전체 리프레시도 수동 API로 제공
- 프론트 Vue는 기존 API 그대로 사용 가능 (/code/list?grcodeCd=xxx)
마무리
이 방식은 공통 코드뿐만 아니라, 자주 변경되지 않는 기준 테이블들에도 적용하기 좋습니다.
추후 Redis 등으로 분산 캐시 확장도 고려할 수 있습니다.
댓글