Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

엘라의 개발 스케치 Note

[TIL] 내일배움캠프 99일차(23.08.21.) - PK vs.FK / 정규표현식 복습 / 좋아요 기능 구현 트러블슈팅 본문

내일배움캠프/TIL

[TIL] 내일배움캠프 99일차(23.08.21.) - PK vs.FK / 정규표현식 복습 / 좋아요 기능 구현 트러블슈팅

엘라랑이 2023. 8. 21. 23:46

To-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월 과제 수행
Comments