[인프런 워밍업 클럽 스터디 1기] 두번째 발자국

[인프런 워밍업 클럽 스터디 1기] 두번째 발자국

1. 2주차 학습한 내용

 

[6일차 - 스프링 컨테이너의 의미와 사용 방법]

1. UserController와 스프링 컨테이너

스프링 빈이란?

  • 서버가 시작되면, 스프링 서버 내부에 컨테이너를 생성한다.

  • 컨테이너 안에 클래스가 들어간다.

  • 이때 다양한 정보도 들어있고, 인스턴스화도 이루어진다.

  • 들어간 클래스를 스프링 빈이라고 한다.

JdbcTemplate 의존성 주입이 되어있다.

  • JdbcTemplate을 스프링 빈으로 등록해주는 설정 코드가 있다.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

서버 시작 시

스프링 컨테이너 시작 -> 기본적으로 많은 스프링 빈 등록 -> 우리가 설정한 스프링 빈(UserController) 등록 -> 의존성 자동으로 설정

스프링 빈으로 등록

  • 각 클래스가 JdbcTemplate을 가져오기 위해 스프링 빈으로 등록한다.

  • 어노테이션 추가한다.

2. 스프링 컨테이너를 왜 사용할까?

Interface 활용

  • BookController는 BookService을 사용한다.

  • BookService는 BookRepository 인터페이스 사용한다.

  • 또 다른 Repository(Repository1, Repository2)가 있다.

     

    • BookService 코드를 변경하지 않고 BookRepository을 변경할 수 있는 방법이 스프링 컨테이너이다.

스프링 컨테이너 사용시

  • 컨테이너가 Repository1 또는 Repository2 중 하나를 선택한 후 BookService를 생성해준다.

     

    • 이러한 방식을 제어의 역전(IoC, Inversion of Control)이라고 한다.

  • 컨테이너가 BookService를 생성할 때, Repository1와 Repository2 중 하나를 선택해서 넣어준다.

     

    • 이러한 과정을 의존성 주입(DI, Dependency Injection)이라도 한다.

우선권을 부여하는 어노테이션 활용

  • @Primary : 우선권을 결정하는 어노테이션을 의미한다.

  • @Primary 어노테이션을 사용 시 Service 코드 변경없이 해당 Repository를 사용할 수 있다.

3. 스프링 컨테이너를 다루는 방법

빈을 등록하는 방법

@Configuration

  • 클래스에 붙이는 어노테이션이다.

  • @Bean을 사용할 때 함께 사용해야 한다.

@Bean

  • 메서드에 붙이는 어노테이션이다.

  • 메서드에서 반환하는 객체를 스프링 빈에 등록한다.

@Configuration과 @Bean 사용하는 경우

  • 외부 라이브러리, 프레임워크에서 만든 클래스를 등록할 때 사용한다.

@Component

  • 주어진 클래스를 컴포넌트로 간주한다.

  • 이 클래스들은 스프링 서버를 시작할때 자동으로 감지된다.

언제 @Component가 사용될까?

  • Controller, Service, Repository가 아닌 추가적인 클래스를 스프링 빈으로 등록할 때 종종 사용된다.

스프링 빈 주입 받는 방법

  • 생성자 사용(@Autowired 생략 가능) -> 가장 권장한다.

  • @Setter와 @Autowired 사용 -> 누군가 Setter를 사용하면 오작동할 수 있다.

  • 필드에 직접 @Autowired 사용 -> 테스트를 어렵게 만드는 요인이다.

@Qualifer("value") 사용

  • 여러가지 후보군이 있을 때 특정 하나를 가져오고 싶을때 사용한다.

  • 스프링 빈을 사용하는 쪽과 스프링 빈을 등록하는 쪽 모두 사용할 수 있다.

    • 적어준 값이 동일한 것끼리 연결된다.

@Primary와 @Qualifer 함께 사용할 경우

우선권을 결정해주는 @Primary와 @Qualifer을 함께 사용했을 때 누가 사용될까?

  • @Qualifer을 사용한다.> 스프링 빈을 사용하는 쪽에서 특정 빈을 지정해준 것의 우선순위를 더 높게 간주한다.

     

 

[7일차 - Spring Data JPA를 사용한 데이터베이스 조작]

1. 문자열 SQL을 직접 사용하면 좋지 않은 이유

  • 문자열을 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느리다.

     

    • 컴파일 시점에 발견되지 않고 런타임 시점에 발견된다.

  • 특정 데이터베이스에 종속적이게 된다.

     

    • DB의 종류마다 문법이 조금씩 다르다.

  • 반복 작업이 많아진다.

     

    • 테이블 하나 만들 때마다 CRUD 쿼리가 항상 필요하다.

  • 데이터베이스의 테이블과 객체는 패러다임이 다르다.

2. JPA(Java persistence API)

JPA란?

  • 자바 진영의 ORM(Object-Relational Mapping) 기술 표준을 의미한다.

  • 객체와 관계형 DB의 테이블을 매핑하여 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙을 의미한다.

Hibernate

  • 규칙을 구현한 구현체를 Hibernate(하이버네이트)라고 한다.

  • Hibernate는 내부적으로 JDBC를 사용한다.

3. 유저 테이블에 대응되는 Entity Class 만들기 - Java 객체와 MySQL Table 매핑하기

JPA 어노테이션

  • @Entity : 저장되고, 관리되어야 하는 데이터를 의미한다.

  • @Id : 해당 필드를 primary key로 간주한다.

  • @GeneratedValue : primary key는 자동 생성되는 값이다.

  • @Column(생략 가능) : 객체의 필드와 Table의 필드를 매핑한다.

기본 생성자 추가

  • 기본 생성자도 추가해야 한다.

@Entity
public class User {

    protected User() {

    }
}

application.yml - JPA 설정 옵션 추가

spring:
  jpa:
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        show_sql: true
        format_sql: true
        dialect: org.hibernate.dialect.MySQL8Dialect

4. Spring Data JPA 사용 - 자동으로 쿼리 전송하기

SQL을 작성하지 않고 유저 생성/조회/업데이트 기능 리팩토링하기

유저 생성 기능 리팩토링하기

Interface UserRepository

  • 인터페이스 UserRepository 생성 후 JpaRepository를 상속 받는다.

UserService

  • save() 메서드에 객체를 삽입하면 Insert SQL이 자동으로 전송된다.

  • 저장이 된 후 User에는 id가 들어간다.

     

유저 조회 기능 리팩토링하기

UserResponse 생성자 추가

  • 코드를 더 깔끔하게 만들기 위해 생성자를 추가한다.

UserService

  • findAll 메서드를 사용하면 모두 유저의 데이터를 조회하는 SQL이 전송된다.

  • 그 결과, List가 반환되고, UserResponse로 변경해서 전달한다.

유저 수정 기능 리팩토링하기

User

  • findById를 사용하면 id를 기준으로 1개의 데이터를 가져온다.

  • Optional의 orElseThrow를 사용해 User가 없을 경우 예외처리한다.

  • 객체를 수정해주고, save 메서드를 호출한다.

  • 자동으로 UPDATE SQL이 전송된다.

SQL을 작성하지 않아도 동작 하는 이유

  • Spring Data JPA를 통해 SQL을 작성하지 않아도 동작한다.

  • Spring Data JPA : 복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리이다.

5. Spring Data JPA 사용 - 다양한 쿼리 작성하기

By 앞에 들어갈 수 있는 구절 정리

  • find : 데이터 1건을 가져온다. 반환 타입은 객체, Optional<타입>이다.

  • findAll : 쿼리의 결과물이 N개인 경우 사용한다. List<타입>을 반환한다.

  • exists : 쿼리 결과가 존재하는지 확인한다. 반환 타입은 boolean이다.

  • count : SQL의 결과 개수를 센다. 반환 타입은 long이다.

각 구절은 and 또는 or로 조합할 수 있다.

By 뒤에 들어갈 수 있는 구절 정리

  • GreaterThan : 초과

  • GreaterThanEqual : 이상

  • LessThan : 미만

  • LessThanEqual : 이하

  • Between : 사이에

  • StartsWith : ~로 시작하는

  • EndsWith : ~로 끝나는

 

[8일차 - 트랜잭션과 영속성 컨텍스트]

1. 트랜잭션(Transaction)

트랜잭션이란?

  • 쪼갤 수 없는 업무의 최소 단위를 의미한다. (모두 성공하거나 실패하는 경우)

트랜잭션 동작 명령어

  • 트랜잭션 시작하기 : start transaction;

  • 트랜잭션 정상 종료하기 (SQL 반영) : commit;

  • 트랜잭션 실패 처리하기 (SQL 미반영) : rollback;

2. 트랜잭션 적용과 영속성 컨텍스트

트랜잭션 적용하기

  • @Transactional 어노테이션을 사용한다.

@Service
public class UserServiceV2 {

    //조회 - readOnly 옵션 사용 가능(SELECT 쿼리)
    @Transactional(readOnly = true)
    public List<UserResponse> getUsers() {
        return userRepository.findAll().stream().map(UserResponse::new).collect(Collectors.toList());

    }
}
  • 메서드가 시작될때 Transactional 시작된다.

  • 메서드 로직이 정상적으로 성공하면 commit되고, 문제가 생길 경우 rollback된다.

트랜잭션을 사용 하는 이유

  • 트랜잭션이 없으면 코드가 한줄 한줄 반영된다.

  • 오류가 생겨도 다른 코드는 반영된다.

주의사항

  • org.springframework.transaction.annotation.Transactional을 붙여야 한다.

  • IOException과 같은 Checked Exception은 롤백이 일어나지 않는다.

영속성 컨텍스트이란?

  • 테이블과 매핑된 Entity 객체를 관리 및 보관하는 역할을 의미한다.

트랜잭션과 영속성 컨텍스트의 관계

  • 트랜잭션 사용 -> 영속성 컨텍스트 시작

  • 트랜잭션 종료 -> 영속성 컨텍스트 종료

영속성 컨텍스트의 특징

  • 변경 감지(Dirty Check) : 영속성 컨텍스트 안에서 확인된 Entity는 명시적으로 save하지 않아도 변경을 감지해서 자동으로 저장한다.

  • 쓰기 지연 : DB의 INSERT/UPDATE/DELETE SQL을 바로 전송하지 않고, 트랜잭션이 commit될 때 SQL을 모아서 한번만 전송한다.

  • 1차 캐싱 : ID를 기준으로 Entity를 기억한다. 최초 1회만 쿼리가 전송되고, 나머지는 보관하고 있는 데이터를 활용한다. 이렇게 반환된 객체는 동일하다.

 

[9일차 - 조금 더 복잡한 기능을 API로 구성하기]

1. 책 생성/대출/반납 기능 API 개발하기

  • book 테이블 및 객체 생성, DTO, Repository, Service, Controller 구현

  • 대출 기록에 대한 Table 추가, 대출 기록 Table에 대한 객체 생성, DTO, Repository, Service, Controller 구현

  • 생성한 테이블로 구현이 충분하지만, DTO를 새로 만드는 게 낫다.

    • 다른 기능들 중 한 기능에 변화가 생길 경우 더 유연하게 side-effect가 없이 대처가 가능하기 때문이다.


2. 미션

네 번째 과제(4일차)

다섯 번째 과제(5일차)


3. 회고

1주차보다 학습한 내용이 많아진 만큼 정리를 잘하고 공부를 많이 해야겠다고 느꼈다. 금요일에 해주신 특강도 너무 도움이 되었다. 내용이 나한테는 아직 어려웠지만 다른 사람들의 코드를 보면서 나도 좀 더 고민해보고 코드를 짜고 과제도 해봐야겠다.

댓글을 작성해보세요.

채널톡 아이콘