-
Notifications
You must be signed in to change notification settings - Fork 0
Proxy객체를 사용해 쿼리횟수 줄이기
채팅 기능을 개발하던 도중 메세지를 보낼때 마다 chatRoom
을 조회하고 chatMessage
를 삽입하는 2번의 쿼리가 발생했습니다.
특히 채팅 메세지는 자주발생하는 이벤트 인 만큼 메세지를 보낼때 마다 2번의 쿼리가 발생한다는 점에서 개선이 필요하다 생각이들었습니다.
@Transactional
public ChatMessageDTO createChat(Long roomId, ChatMessageDTO dto){
ChatRoom room = chatRoomRepository.findById(roomId).orElseThrow(()->new IllegalArgumentException("채팅방이 없습니다"));
ChatMessage message = ChatMessage.builder()
.sender(dto.getSender())
.message(dto.getMessage())
.room(room)
.sendTime(dto.getSendTime())
.build();
chatMessageRepository.save(message);
return dto;
}
ChatMessage
를 보낼때 ChatRoom
을 조회 하는 이유는
1, ChatMessage
객체는 해당 메시지가 어느 채팅방에서 보낸 것인지를 알아야 하므로,
room
필드를 통해 ChatRoom
엔티티를 참조하게 됩니다. 이 필드를 통해 ChatMessage
와 ChatRoom
간의 관계를 명시적으로 설정해야 하며,
2, ChatRoom
객체가 없을시 발생하는 참조 무결성 문제 때문에 메세지를 보낼때마다 ChatRoom
을 조회한다는 점
이러한 이유로 인해 ChatRoom
을 조회해야합니다.
1, 어느 채팅방에서 보낸 것인지를 알아야 한다는 점에서 → 프록시 객체 사용
프록시 객체를 사용하면, 실제 ChatRoom
데이터를 즉시 조회하지 않고도 ChatRoom
과의 관계를 설정할 수 있습니다.
2, 참조 무결성을 유지하기 위해 → 데이터베이스 레벨에서 제약 조건으로 검증
데이터베이스에서 참조 무결성을 유지하기 위해, 외래 키 제약 조건을 사용하여 ChatRoom
이 존재하는지 검증합니다.
이렇게 하면, 데이터베이스는 ChatRoom
이 존재하지 않으면 메시지를 저장할 수 없도록 보장합니다.
특히, 프록시 객체를 사용할 경우 채팅방에 대한 추가 조회 쿼리를 실행하지 않게 되어 성능을 최적화할 수 있다는 점에서 이 방식을 선택했습니다.
1,먼저 EntityManager를 빈으로 등록합니다.
@Autowired
private EntityManager entityManager;
2,이후, getReference 메서드를 사용하여 ChatRoom에 대한 프록시 객체를 조회합니다
ChatRoom room = entityManager.getReference(ChatRoom.class, roomId);
3,이렇게 조회된 프록시 객체를 ChatMessage 객체의 room 필드에 참조시킵니다
ChatMessage message = ChatMessage.builder()
.sender(dto.getSender())
.message(dto.getMessage())
.room(room)
.sendTime(dto.getSendTime())
.build();
프록시 객체를 사용 했을때 문제점을 고민한 결과
ChatRoom
은 DB에서 조회하는것이 아닌 프록시 객체를 사용하는 것이므로 참조무결성이 보장되지 않는다는 점 이였습니다,
그래서 DB레벨에서 제약조건으로 검증했습니다.
ALTER TABLE chat_message
ADD CONSTRAINT fk_room_id
FOREIGN KEY (room_id) REFERENCES room(id) ON DELETE CASCADE;
이렇게 프록시 객체를 활용해 불필요한 데이터베이스 쿼리 실행을 줄이고, 참조 무결성은 데이터베이스에서 관리하도록 최적화하였습니다.
프록시 객체를 사용하기전
프록시 객체를 사용한 후
예상대로 결과가 2회에서 1회로 최적화가 되었습니다.