엘라의 개발 스케치 Note
[TIL] 내일배움캠프 99일차(23.08.21.) - PK vs.FK / 정규표현식 복습 / 좋아요 기능 구현 트러블슈팅 본문
내일배움캠프/TIL
[TIL] 내일배움캠프 99일차(23.08.21.) - PK vs.FK / 정규표현식 복습 / 좋아요 기능 구현 트러블슈팅
엘라랑이 2023. 8. 21. 23:46To-do
- CS 스터디
- 기술면접 대비 공부
- 최종 프로젝트 회의 -> 역할 분담
- 최종 프로젝트 작성 -> 페스티벌, 리뷰, 댓글 좋아요 기능 구현 / 소셜로그인 기능 코드 리뷰(오류 해결)
- 알고리즘 스터디
TIL
< PK vs. FK >
Primary Key는 관계형 데이터베이스에서 각 레코드를 고유하게 식별하기 위한 필드로, 중복되지 않는 값으로 설정됩니다. 이를 통해 데이터의 무결성을 보장하고 검색 속도를 높일 수 있습니다.
반면, Foreign Key는 두 개의 테이블 간의 관계를 정의하는 필드로, 다른 테이블의 기본 키를 참조하여 데이터 간의 관계를 설정하고 유지하는 역할을 합니다. 이를 통해 데이터의 일관성과 무결성을 보장할 수 있습니다. 두 키 모두 데이터베이스 시스템의 구조를 유지하고 데이터 관리를 용이하게 합니다.
< 정규표현식 복습 >
- 정규 표현식(regular expression, 간단히 regexp 또는 regex, rational expression) 또는 정규식은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다. 정규 표현식은 많은 텍스트 편집기와 프로그래밍 언어에서 문자열의 검색과 치환을 위해 지원하고 있다.
- 기본 개념
- `|` “또는”
- 여러 항목 중 선택을 하기 위해 구분한다. 이를테면 `gray|grey`는 "gray" 또는 "grey"와 일치한다.
- `( )` 그룹 묶기
- 괄호를 사용하면 연산자의 범위와 우선권을 정의할 수 있다. 이를테면 `gray|grey`와 `gr(a|e)y`는 "gray"나 "grey" 집합을 둘 다 기술하는 동일 패턴이다.
- 양의 지정
- `?` 물음표는 0번 또는 1차례까지의 발생을 의미한다. 이를테면 `colou?r`는 "color"와 "colour"를 둘 다 일치시킨다.
- `*` 별표는 0번 이상의 발생을 의미한다. 이를테면 `ab*c`는 "ac", "abc", "abbc", "abbbc" 등을 일치시킨다.
- `+` 덧셈 기호는 1번 이상의 발생을 의미한다. 이를테면 "abc", "abbc", "abbbc" 등을 일치시키지만 "ac"는 일치시키지 않는다.
- `{n}` 정확히 n 번만큼 일치시킨다.
- `{min,}` "min"번 이상만큼 일치시킨다.
- `{min,mix}` 적어도 "min"번만큼 일치시키지만 "max"번을 초과하여 일치시키지는 않는다.
- 기본 및 확장 표준 문법
메타문자 | 기능 | 설명 |
. | 문자 | 1개의 문자와 일치한다. 단일행 모드에서는 새줄 문자를 제외한다. |
[ ] | 문자 클래스 | "["과 "]" 사이의 문자 중 하나를 선택한다. "¦"를 여러 개 쓴 것과 같은 의미이다. 예를 들면 [abc]d는 ad, bd, cd를 뜻한다. 또한, "-" 기호와 함께 쓰면 범위를 지정할 수 있다. "[a-z]"는 a부터 z까지 중 하나, "[1-9]"는 1부터 9까지 중의 하나를 의미한다. |
[^ ] | 부정 | 문자 클래스 안의 문자를 제외한 나머지를 선택한다. 예를 들면 [^abc]d는 ad, bd, cd는 포함하지 않고 ed, fd 등을 포함한다. [^a-z]는 알파벳 소문자로 시작하지 않는 모든 문자를 의미한다. |
^ | 처음 | 문자열이나 행의 처음을 의미한다. |
$ | 끝 | 문자열이나 행의 끝을 의미한다. |
\n | 일치하는 n번째 패턴 | 일치하는 패턴들 중 n번째를 선택하며, 여기에서 n은 1에서 9 중 하나가 올 수 있다. |
- 문자 클래스
ASCII | 설명 |
[A-Za-z0-9] | 영숫자 |
[A-Za-z0-9_] | 영숫자 + "_" |
[^A-Za-z0-9_] | 낱말이 아닌 문자 |
[A-Za-z] | 알파벳 문자 |
[ \t] | 공백과 탭 |
(?<=\W)(?=\w)|(?<=\w)(?=\W) | 낱말 경계 |
[\x00-\x1F\x7F] | 제어 문자 |
[0-9] | 숫자 |
[^0-9] | 숫자가 아닌 문자 |
[\x21-\x7E] | 보이는 문자 |
[a-z] | 소문자 |
[\x20-\x7E] | 보이는 문자 및 공백 문자 |
[][!"#$%&'()*+,./:;<=>?@\^_`{|}~-] | 구두점 |
[ \t\r\n\v\f] | 공백 문자 |
[^ \t\r\n\v\f] | 공백이 아닌 모든 문자 |
[A-Z] | 대문자 |
[A-Fa-f0-9] | 16진수 |
\\. | 마침표는 정규 표현식 내에서 특별한 역할을 수행하므로 이를 문자 자체로 인식하도록 이스케이프(\\) 처리 |
< 좋아요 기능 구현 트러블슈팅 >
1. 좋아요 수 반환에 대한 고민
- Problem ? 상위 Response에 좋아요 수를 반환하는 방법 두 가지 중 어떤 방법이 더 DB나 성능에 좋을지 고민하게 됨
1. Comment Entity -> DB 에 likeCnt열을 추가해서 좋아요 추가/취소가 발생할 때마다 'CommentLike 추가/삭제 + comment Entity'를 수정하는 방법
2. Comment Entity는 그대로 두고 -> 좋아요 추가/취소가 발생할 때마다 'CommentLike 추가/삭제' -> commentResponseDto에서 commentLike 갯수를 세는 방법
- Try. 튜터님께 질의하여 해결 및 결정
* 정규화(중복 데이터 최대한 저장하지 않도록 하는 게 목적) 관점에서 1번 방법은 중복된 데이터를 저장하는 방법이므로 옳지 않음.
-> commentLike 갯수를 세는 게 성능에 무리가 갈까 싶어 여쭤봄 -> comment를 가져올 때 commentLike를 가져오게 되므로 현재의 프로젝트에서 count()가 크게 무리가 될 것으로 보이지 않음
-> 하지만, 현업에서는 성능 최적화를 진행하기 위하여 반정규화를 진행하기도 함
-> 정규화 관점, 성능 최적화 등을 고려하여 우리의 프로젝트에 맞는 방법을 선택하여 진행하시면 된다는 답변을 받음
- Solution !
결론) commentLike를 어차피 comment를 불러올 때 가져온다면
-> 우리의 프로젝트가 count() 메소드로 성능에 크게 무리를 가져올 만큼의 규모는 아니라 생각되어 정규화 관점을 지키고자 2번 방법으로 진행
2. 좋아요 취소 시 Response에 좋아요 수가 줄어들지 않는 오류 해결
- Problem ? 좋아요 취소 시 Response에 좋아요 수가 줄어들지 않는 오류가 발생함
// 리뷰 좋아요 취소
@Override
@Transactional
public CommentResponseDto deleteCommentLike(Long commentId, User user) {
Comment comment = findComment(commentId);
// 좋아요를 누르지 않은 경우 오류 반환
if (findCommentLike(user, comment) == null) {
throw new IllegalArgumentException("좋아요를 누르시지 않았습니다.");
}
// 오류가 나지 않을 경우 해당 페스티벌에 좋아요 취소
commentLikeRepository.delete(findCommentLike(user, comment));
return new CommentResponseDto(comment);
}
- Try. 코드를 자세히 보니 transaction commit이 메소드 완전히 종료 후 반영되므로 좋아요 수가 이전에 존재하던 수로 가져오게 되는 문제였음
- Solution! ResponseDto 반환 전 transaction commit을 한번 먼저 하는 방법으로 해결
// 댓글 좋아요 취소
@Override
public CommentResponseDto deleteCommentLike(Long commentId, User user) {
CommentResponseDto response = transactionTemplate.execute(status -> {
Comment comment = findComment(commentId);
// 좋아요를 누르지 않은 경우 오류 반환
if (findCommentLike(user, comment) == null) {
throw new IllegalArgumentException("좋아요를 누르시지 않았습니다.");
}
// 오류가 나지 않을 경우 해당 댓글에 좋아요 취소
commentLikeRepository.delete(findCommentLike(user, comment));
// 여기에서 커밋을 수행 (트랜잭션 내에서 커밋 또는 롤백을 수행할 수 있음)
status.flush();
// CommentResponseDto 생성 후 반환
return new CommentResponseDto(comment);
});
// 위에서 커밋이 수행되었으므로 CommentResponseDto에서 새로운 likeCnt를 가져올 수 있음
return response;
}
- Problem? 해당 방법이 자주 사용하지 않는 방법인 거 같아 튜터님께 해당 방법이 문제가 없는지 여쭤봄 -> 사이드 이펙트가 있을지 검토하신 후 알려주시기로 하셨음!
Next...
- 최종 프로젝트 회의 및 작성
- CS 공부
- 기술면접 대비 공부
- JPA 강의 듣기
- 알고리즘 문제 풀기
- 뚜까패 스터디 발표 자료 정리
- 원티드 프리온보딩 백엔드챌린지 9월 과제 수행