낙서장

클래스를 설계할때 어떤 순서로 작성해가야 하는가에 대한 나의 생각

AOIME 2025. 8. 8. 13:35

|학습 목표

 

지금 내가 만드는 프로젝트를 만드는데 어떤 설정을 해야하는지 파악하고 쓸 수 있도록하자

 

1. 첫번째로 application.yml 파일을 어떤 구성을 작성해야하는지 파악하자

 

2. OSIV(Open Session In View) = false를 설정하며 
어떤 방식으로 구동 되야 하는지 파악하기 

 

3. 파악했다면 어떤 순서대로 짜야 코드의 흐름이 될까 생각하고 그 순서대로 적어가면 내가 쓴 코드의 이해도를 높이기

 

 

1. 첫번째로 application.yml 파일을 어떤 구성을 작성해야하는지 파악하자

더보기
#==========================서버 포트 설정==========================================
server:                         # 서버가 실행될 포트 번호(브라우저에서 접속할 포트)
  port: 8080                    # 기본값은 8080이지만 명시적으로 지정해주는게 좋음
  
# ==========================Spring 설정=====================================
spring:
  application:                     
    name: class-image-server                 #이 애플리케이션 이름(로깅 등에서 식별용으로 사용됨)
                                             # 예: 클라우드 서비스에서 서비스 명으로 활용 가능
 # ======================= H2 데이터베이스 설정 ==============                                             
  datasource:
    url: jdbc:h2:mem:testdb            # H2 데이터베이스의 접속 URL
                                       # 'mem'은 메모리 기반 DB, 서버 종료 시 데이터 사라짐
                                       # testdb는 DB 이름
                                       
    driver-class-name: org.h2.Driver # H2 DB용 드라이버 클래스 (JDBC 드라이버)
    username: sa                     # 기본 사용자명 (H2의 기본값)
    password:                        # 비밀번화는 비워둠(보안에 민감한 상황이 아니기 때문에)
    
  h2:
    console:
      enabled: true                  # H2 웹 콘솔을 사용할지 여부(true면 웹에서 접속 가능)
      path: /h2-console              # 브라우저에서 접속할 경로 (/h2-console)
      
      # 예: http://localhost:8080/h2-console로 접속 가능
      # 개발 중 데이터 확인, 테스트용으로 매우 유용
      
# ================= JPA (자바 ORM) 설정 =======================
  jpa:
    hibernate:
      ddl-auto: create-drop            # 실행 시 DB 테이블 생성 후, 종료 시 삭제
                                       # 개발/ 테스트용으로 적합
                                       #옵션 종류:
                                       # - none: 아무 작업 안 함
                                       # - create: 실행 시 테이블 생성
                                       # - update: 변경 사항만 반영
                                       # - create-drop: 생성 후 종료 시 삭제
                                       # - validatg: 스키마 유효성 검증만
    
    show-sql: true                     # 실행되는 SQL 쿼리를 콘솔에 보여줌
                                       # 디버깅/ 학습에 매우 좋음
    
    properties:
      hibernate:
        formate_sql: true              # 출력되는 SQL을 보기 좋게 정렬함(가독성 up)
        dialect: org.hibernate.dialect.H2Dialect
                                       # Hibernate가 사용할  DB 방언 (dialect)
                                       # H2에 최적화된 SQL을 생성하기 위해 설정
#==============================로깅 설정=================================
logging:
  level:
    com.tenco.class_image_server: DEBUG # 내프로젝트 패키지의 로그 레벨을 DEBUG로 설정
                                        # DEBUG는 가장 상세한 로그 단계 중 하나( 개발 시 유용)
    org.springframework.web: DEBUG      # Spring 웹 관련 로그도 상세히 출력
    org.hibernate.SQL: DEBUG            # Hibernate가 생성한 SQL문을 상세히 출력

 

용어 영어 설명

포트 Port 서버가 클라이언트 요청을 받을 통신 창구
메모리 DB In-memory DB 서버 실행 중에만 존재하는 데이터베이스
드라이버 클래스 Driver Class JDBC로 DB에 접속하기 위한 클래스
ORM Object-Relational Mapping 객체와 관계형 DB를 매핑해주는 기술
방언 Dialect DB 종류에 따라 SQL이 조금씩 다르기 때문에, Hibernate가 어떤 DB를 사용하는지 알려주는 설정
콘솔 Console 웹 기반의 인터페이스. DB 콘솔은 웹 브라우저에서 SQL을 직접 실행 가능
  • erver.port → 서버 포트 설정
  • spring.datasource → DB 연결 설정
  • h2.console → 브라우저에서 DB 확인 가능하게
  • jpa.hibernate.ddl-auto → 테이블 생성/삭제 자동화
  • logging.level → 로그 상세도 조절 (디버깅용)

 

2. OSIV(Open Session In View) = false를 설정하며 
어떤 방식으로 구동 되야 하는지 파악하기 

더보기

OSIV(Open Session In View)

OSIV는 영속성 컨텍스트를 뷰까지 열어둔다는 뜻이다. 영속성 컨텍스트가 살아있으면 엔티티는 영속 상태로 유지된다.

따라서 지연 로딩을 사용할 수 있다. 참고로 OSIV는 Hibernate 용어다. 

JPA는 OEIV(Open EntityManager In View)라 하지만 관례상 모두 OSIV로 부른다.

 

 

과거 OSIV: 요청 당 트랜잭션

OSIV의 핵심은 뷰에서도 지연 로딩이 가능하도록 하는 것이다. 가장 단순한 구현 방법은 클라이언트의 요청이 들어오자마자

서블릿 필터나 스프링 인터셉터에서 트랜잭션을 시작하고 요청이 끝날 때 트랜잭션도 끝나는 것이다. 이것을 요청 당 트랜 잭션방식의 OSIV라 한다.

 

 

 

 1. 요청이 들어오면 서블릿 필터나 스프링 인터셉터에서 영속성 컨텍스트를 만들면서 트랜잭션을 시작한다.

2.Controller, Service, Repository 층에서 모두 영속성 컨텍스트가 유지된다.

3. 조화된 엔티티 또한 뷰까지 영속 상태를 유지하므로 지연 로딩이 가능하다. 미리 초기화할 필요가 없다.

     - 뷰에서도 지연 로딩을 할 수 있으므로 FACACDE 계층 없이도 뷰에 독립적인 서비스 계층을 유지할 수 있다.

4. 요청이 끝날 때 트랜잭션과 영속성 컨텍스트를 함꼐 종료한다.

 

문제점 

요청 당 트랜잭션 방식 OSIV가 가지는 문제점은 컨트롤러난 뷰 같은 프레젠테이션 계층이 엔티티를 변경할 수 있다는 점이다. 예를 들어 , 보안상의 이유로 고객 이메일을 Base64로 인코딩해서 출력해야 한다고 가정하자. 렌더링할 때 뷰에 넘겨주었는데 개발자 의도와는 다르게 DB의 고객 이메일까지 인코딩된 주소로 변경되었다.

 

요청 당 트랜잭션 방식은 뷰를 렌더링한 후에 트랜잭션을 커밋한다. 트랜잭션을 커밋하면 당연히 영속성 컨텍스트를 flush dirty check 기능이 동작하여 변경된 엔티티의 값을 DB에 반영해버린다. 결국 고객 데이터가 변경되는 심각한 문제가 발생한다.

 

해결법 

이에 대한 해결법으로는 모두 엔티티를 직접 노출하느 대신에 다른 방식으로 읽기 전용 메소드 혹은 객체를 사용하는 방법이 있다 그러한 방식에는 여러가지가 잇따.

 

1. 엔티티를 읽기 전용 인터페이스로 제공: 일기 전용 메서드(getter)만 제공하느 인테페이스를 만든다.

2. 엔티티 래핑: 1 번과 유사한 방식으로 , 읽기 전용 메서드(getter) 만 가지고 있는 엔티티를 감싼 객체(EntityWrapper)를 만든다.

3. DTO만 반환 : 가장 전통적인 방식으로 엔티티 대신 단순한 데이터 전달 객체(DTO; Data Transfer Object)를 생성해서 반환한다. 하지만. 이 방법은 OSIV의 장점을 살릴 수 없고 엔티티를 거의 복사한 듯한 DTO 클래스도 하나 더 만들어야 한다.

 

이러한 해결법들이 존재하지만 모두 코드량이 증가한다는 단점이 있다. 차라리 프레젠테이션 계층에서 엔티티를 수정하면 안된다고 개발자끼리 합의하는 것이 더 실용적일 수 있다 .또는 적절한 도구를 사용하여 컴파일 단계에서 프레젠테이션 계층에서 사용되는 setter를 잡아내는 방식도 있지만 쉽지는 않다.

 

스프링 OSIV: 비즈니스 계층 트랜잭션

 이런 문제점을 어느정도 보완해서 비즈니스 계층에서만 트랜잭션을 유지하는 방식의 OSIV를 사용한다. 스프링 프레임워크가 제공하는 OSIV가 바로 이 방식을 사용하는 OSIV이다.

 

1. 클라이어트 요청이 들어오면 서블릿 필터나 스프링 인터셉터에서 영속성 컨텍스트를 생성한다. 단 이때 트랜잭션은 시작하지 않는다. 

2. 서비스 계층에서 @Transactional로 트랜잭션을 시작할 때 1번에서 미리 생성해둔 영속성 컨텍스트를 찾아와서 트랜잭션을 시작한다. 

3. 서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이때 트랜잭션을 끝내지만 영속성 컨텍스트는 종료하지 않는다. 

4. 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속성 상태를 유지한다.

5. 서블릿 필터나 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료한다. 이때 플러시를 호출하지 않고 바로 종료한다.

 

스프링 OSIV 특징

스프링이 제공하는 OSIV를 사용하면 프레젠테이션 계층에서는 트랜잭션이 없으므로 엔티티를 수정할 수 없다. 따라서 프레젠테이션 게층에서 엔티티를 수정할 수 있는 기존 OSIV의 단점을 보완했다. 그리고 트랜잭션 없이 읽기를 사용해서 프레젠테이션 계층에서 지연 로딩 기능을 사용할 수 있다.

- 영속성 컨텍스트를 프레젠테이션 계층까지 유지한다.

- 프레젠테이션 계층에서는 트랜잭션이 없으므로 엔티티를 수정할 수 없다.

- 프레젠테이션 계층에는 트랜잭션이 없지만 트랜잭션 없이 읽기를 사용해서 지연 로딩을 할 수 잇다.

 

3. 파악했다면 어떤 순서대로 짜야 코드의 흐름이 될까 생각하고 그 순서대로 적어가면 내가 쓴 코드의 이해도를 높이기

더보기

작성 순은 이러한 순서가 이해를 더 쉽게 돕느다고 생각한다.

Entity를 생성 ------------> request ------------------> JpaRepository -----------------> response------------->service------->controller 

각자 어떤 역활을 하면서 넘겨주고 생성될지를 생각해가면서 작성하는게 나의 이해흐름도에 도움이 된다. 무작정따라 쳐도 

순서정도는 알고 작성하면서 왜 이 순으로 적어야할까 고민하면서 치자.!!!!!!!!!!!!!!!!!!!!!!!!!!

 

 

728x90