패스트캠퍼스

패스트캠퍼스 환급챌린지 21일차 : 9개 도메인 프로젝트로 끝내는 백엔드 웹 개발 (Java/Spring) 초격차 패키지 Online 강의 후기

이태우(1990년) 2025. 3. 25. 23:31

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

 

공부 시작 시각 인증

공부 시작 시각 인증

수강 인증 사진

수강 인증 사진

JPA란?

  • Java Persistence API
  • Java 진영에서 ORM 기술 표준으로 사용하는 인터페이스 모음

ORM이란?

  • Object Relational Mapping
  • Class 객체와 RDB 테이블을 자동으로 매핑 해주고 영속화함.

ORM을 통해 RDB와 객체의 간극을 줄인다.

  1. 추상화
    • 추상 계층을 제공해서 객체를 테이블 형태로 변환해 주기 때문에 SQL 문을 쓰지 않고도 개발 가능
  2. 생산성
    • 반복되는 CRUD 코드가 줄어 들어, 생산성 증가
  3. 유지보수
    • ERD 의존도 낮춰, 유지보수 증가 
  4. 보안
    • SQL 인젝션, 쿼리 조작 등 보안 문제에서 자유로움.

영속성 컨테스트: 엔티티를 영구 저장하는 환경

영속성 컨테스트 특징

1차 캐시: ID를 기준으로 1차 캐시에서 엔티티 값을 반환해 준다.

쓰기 지연: 트렌잭션을 지원하며, 트렌잭션이 끝나면 쿼리가 진행된다.

동일성 보장: 항상 1L을 같은 트렌잭션 내에서 조회해도 같은 값을 반환해 주며, 실제 메모리 주소도 같은 객체이다.

변경 감지: 스냅샷을 통해 변경 상태를 감지한다.

 

User.java

package org.fastcampus.user.domain;

import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.fastcampus.common.domain.*;

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    @Id
    @Getter
    private Long id;
    @Embedded
    private UserInfo info;
    @Embedded
    private PositiveIntegerCounter followingCount;
    @Embedded
    private PositiveIntegerCounter followerCount;

    public User(Long id, UserInfo userInfo) {
        if (userInfo == null) {
            throw new IllegalArgumentException();
        }

        this.id = id;
        this.info = userInfo;
        this.followingCount = new PositiveIntegerCounter();
        this.followerCount = new PositiveIntegerCounter();
    }

    public void follow(User targetUser) {
        if (targetUser.equals(this)) {
            throw new IllegalArgumentException();
        }

        followingCount.increase();
        targetUser.increaseFollowerCount();
    }

    public void unfollow(User targetUser) {
        if (targetUser.equals(this)) {
            throw new IllegalArgumentException();
        }

        followingCount.decrease();
        targetUser.decreaseFollowerCount();
    }

    private void increaseFollowerCount() {
        followerCount.increase();
    }

    private void decreaseFollowerCount() {
        followerCount.decrease();
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        User user = (User) o;
        return Objects.equals(id, user.id);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(id);
    }

    public String getName() {
        return info.getName();
    }

    public String getProfileUrl() {
        return info.getProfileImageUrl();
    }

    public int followerCount() {
        return followerCount.getCount();
    }

    public int followingCount() {
        return followingCount.getCount();
    }
}

UserInfo.java

package org.fastcampus.user.domain;

import lombok.Getter;

@Getter
public class UserInfo {
    private final String name;
    private final String profileImageUrl;

    public UserInfo(String name, String profileImageUrl) {

        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException();
        }

        this.name = name;
        this.profileImageUrl = profileImageUrl;
    }
}

PositiveIntegerCounter.java

package org.fastcampus.common.domain;

public class PositiveIntegerCounter {
    private int count;

    public PositiveIntegerCounter() {
        this.count = 0;
    }

    public PositiveIntegerCounter(int count) {
        if (count < 0) {
            throw new IllegalArgumentException();
        }
        this.count = count;
    }

    public void increase() {
        this.count++;
    }

    public void decrease() {
        if (count <= 0) {
            return;
        }
        this.count--;
    }

    public int getCount() {
        return count;
    }
}

UserEntity.java

package org.fastcampus.user.repository.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.fastcampus.common.domain.*;
import org.fastcampus.user.domain.*;

@Entity
@Table(name = "community_user")
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String profileUrl;
    private Integer followerCount;
    private Integer followingCount;

    public UserEntity(User user) {
        this.id = user.getId();
        this.name = user.getName();
        this.profileUrl = user.getProfileUrl();
        this.followerCount = user.followerCount();
        this.followingCount = user.followingCount();
    }

    public User toUser() {
        return User.builder()
                .id(id)
                .info(new UserInfo(name, profileUrl))
                .followerCount(new PositiveIntegerCounter(followerCount))
                .followingCount(new PositiveIntegerCounter(followingCount))
                .build();
    }
}

학습 인증샷

학습 인증샷

공부 종료 시각 인증

공부 종료 시각 인증

https://bit.ly/4hTSJNB