발견 시점: 채팅방 목록(나의 채팅방) 조회 API를 프로파일링할 때
현상:
- ChatRoomQueryService.getMyChatRooms()
호출 시 채팅방 개수 N만큼 findTopByChatRoomOrderBySentAtDesc()
쿼리 수행 (N+1 문제)
TransactionSynchronizationManager.registerSynchronization(...)
코드 존재영향 범위: 채팅방 입장·목록 조회 시 DB 부하 증가, 유지보수시 Broadcast 로직 수정 시 누락 위험
registerSynchronization
사용 지점 카운트선택 이유:
- JPQL 커스텀 DTO 조회로 N+1 제거
사용 기술/라이브러리:
- Spring Data JPA 커스텀 쿼리 (@Query
+ new
DTO 생성자)
Optional
·Collectors
구체적 접근 방식:
1. ChatRoomRepository
에 채팅방 목록과 최신 메시지, 미확인 개수까지 함께 조회하는 JPQL 메서드 추가
ChatRoomQueryService
에서 스트림 매핑 대신 이 메서드 사용ChatMemberEventService.scheduleBroadcast(roomId)
같은 헬퍼로 추출@Query("""
SELECT new team.budderz.buddyspace.api.chat.response.rest.ChatRoomSummaryResponse(
r.id, r.name, m.content, m.messageType, m.sentAt, COUNT(c) - :readCount
)
FROM ChatRoom r
JOIN r.participants p
LEFT JOIN ChatMessage m ON m = (
SELECT x FROM ChatMessage x
WHERE x.chatRoom.id = r.id
ORDER BY x.sentAt DESC
LIMIT 1
)
LEFT JOIN r.chatMessages c
WHERE p.user.id = :userId AND p.isActive = true
GROUP BY r.id, m.content, m.messageType, m.sentAt
""")
List<ChatRoomSummaryResponse> findSummariesWithLastMessageAndUnread(
@Param("userId") Long userId,
@Param("readCount") Long readCount
);
ChatRoomQueryService.getMyChatRooms()
를 위 메서드 호출로 변경ChatRoomCommandService
와 ChatRoomServiceFacade
내 Broadcast 등록 코드를 ChatMemberEventService.registerBroadcast(roomId)
로 통합 participants.stream()
.map(this::toChatRoomSummaryResponse)
.toList();
return chatRoomRepository.findSummariesWithLastMessageAndUnread(userId, lastReadId);
public void scheduleBroadcast(Long roomId) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override public void afterCommit() {
this.broadcastMembers(roomId);
}
}
);
}
기존 registerSynchronization
호출부는 모두 이 메서드로 대체
ChatRoomQueryService
복잡도(Cyclomatic Complexity) 12 → 6