현재 진행하고 있는 프로젝트에서 typeORM을 사용중인데 특정 값을 변경하고 update를 할 때나 insert 할 때 모두 repository의 save()함수를 사용하고 있었다
increaseLikeCount(comment: Comment): Promise<Comment> {
comment.likeCount += 1;
return this.commentRepository.save(comment);
}
하지만 이 함수의 실제 동작 쿼리를 보면 SELECT 구문과 UPDATE 구문 두개의 구문이 실행 되는 것을 볼 수 있었다
좋아요수나 조회수 등을 증감시킬때는 값만 변경하면 되는데 불필요한 SELECT 구문이 실행되는걸 최적화 하기로 하였다
repository에서 기본으로 제공하는 save() 함수가 느리니 새로운 함수를 만들어 UPDATE 구문만이 실행되도록 하였다
async increaseViewCount(id: number): Promise<void> {
await this.query(
`UPDATE article SET view_count = view_count + 1 WHERE id=${id}`,
);
}
raw query를 활용하는것이 ORM을 사용하는데 아름답지 못한 방법이라고 생각이 되어 좀 더 다른 방법을 알아보기로 했다
https://github.com/typeorm/typeorm/issues/680
typeORM에 issue로 나와 비슷한 질문을 하신 분이 계셔 해당 issue에서 많은 정보를 얻을 수 있었다
save() 함수를 사용하게 되면 해당 객체가 존재하지 않을경우 INSERT를 존재 할 경우는 UPDATE를 하는 동작을 수행하기 때문에 해당 객체가 존재하는지 여부를 판단하기 위해 SELECT 구문을 사용하는 것 이었다
하지만 현재 서비스에서 save()를 사용하고 있던곳의 로직은 UPDATE만 이루어지므로 save()를 활용하는것은 비효율적이었다
또한 save()를 하면서 인자로 객체 전체를 넘겨주게되면 우리는 count값 한개를 변경하기 위한 것이지만 모든 값에대한 update가 이루어지게 되어 굉장히 비효율적이라고 한다
async increaseLikeCount(comment: Comment): Promise<Comment> {
comment.likeCount += 1;
await this.commentRepository.update(comment.id, {
likeCount: comment.likeCount,
});
return comment;
}
그런데 위의 답변이 어째서인지 비추천이 9개나 찍혀있었고 그 이유가 뭔지 알아보았다
그 이유는 해당 issue에 더 아래 답변에서 찾을 수 있었다
값을 model 객체에서 가져와 수정할 경우 그 사이에 객체의 값에 변화가 생길 수 있어 트랜잭션의 고립성을 보장 할 수 없기 때문이라고 한다
async increaseLikeCount(comment: Comment): Promise<Comment> {
await this.commentRepository.update(comment.id, {
likeCount: () => 'like_count + 1',
});
comment.likeCount += 1;
return comment;
}
그래서 최종적으로 해당 코드와 같이 db에서의 값을 기준으로 +1을 하도록 하였다
db에서는 자체적으로 고립성을 보장하고 queue를 지원하기 때문이다
주의할 점은 db의 값을 읽어야하기 때문에 속성값을 model에 정의된 속성값이 아닌 db table에 정의된 속성값으로 명시해야 한다
학부에서 정말 여러가지 분야에 다 관심이 있어 최대한 모든 전공을 들으려고 했었는데 유일하게 듣지 못한 과목이 DB였다
그런데 최근 여러가지 프로젝트를 진행하면서 DB를 사용할 일이 많아지니 그 선택이 굉장히 후회스럽다
DB를 설계하고 ERD를 그리는 과정부터 ORM이라는 개념까지 처음 겪어보니 굉장히 주먹구구식으로 진행을 했다
이와 관련된 내용을 배울 수 있는 기회가 생긴다면 추후에라도 꼭 배워보고 싶은 내용이 됐다