인프런 워밍업 클럽 회고 2
인프런 워밍업 클럽 회고 2
서론
벌써 강의를 들은지 2주차가 지나간다. 강의와 스터디를 하면서 배운 내용을 잊지 않도록 주마다 블로그에 정리하려고 한다.
섹션 3 : 역할의 분리와 스프링 컨테이너
UserController와 스프링 컨테이너
-
UserController는 JdbcTemplate에 의존한다.
-
@RestController가 UserController 클래스를 API의 진입지점으로 만들어주고, 스프링 빈으로 등록시킨다.
- 서버 시작 후 동작 과정
- 스프링 컨테이너(클래스 저장소)가 시작된다.
- 기본적으로 많은 스프링 빈들이 등록된다.
- 우리가 설정해준 스프링 빈이 등록된다.
- 필요한 의존성이 자동으로 설정된다.
- 서버 시작 후 세개의 클래스 동작 과정
- JdbcTemplate을 의존하는 UserRepository가 스프링 빈으로 등록된다.
- UserRepository를 의존하는 UserService가 스프링 빈으로 등록된다.
- UserService를 의존하는 UserController가 스프링 빈으로 등록된다.
스프링 컨테이너를 사용하는 이유 다음 시간에
스프링 컨테이너를 왜 사용할까?
-
스프링 컨테이너를 사용하면 컨테이너가 서비스를 대신 인스턴스화 하고, 알아서 레포지토리를 결정해준다.
-
의존성 주입 (DI, Dependency Injection) : 컨테이너가 선택해 서비스에 넣어주는 과정.
-
제어의 역전 (IoC, Inversion of Control) : 스프링 컨테이너가 어떤 구현 타입을 쓸지 대신 결정해주는 방식.
-
@Primary 를 활용해서 어떤 Repository가 주입될지 조절할 수 있다.
스프링 컨테이너를 다루는 방법
-
빈을 등록하는 방법
-
@RestController, @Service, @Repository를 사용하는 방법.
-
@Configuration + @Bean를 사용하는 방법
- @Configuration : 클래스에 붙이는 어노테이션, @Bean과 함께 사용한다.
- @Bean : 메소드에 붙이는 어노테이션, 메소드에서 반환되는 객체를 스프링 빈에 등록한다.
-
- @Service, @Repository를 사용하는 경우
- 개발자가 직접 만든 클래스를 스프링 빈으로 등록할 때 사용한다.
- @Configuration + @Bean을 사용하는 경우
- 외부 라이브러리, 프레임워크에서 만든 클래스를 등록할 때 사용한다.
-
@Component : 주어진 클래스를 컴포넌트로 간주하여, 이 클래스들은 스프링 서버가 뜰 때 자동으로 감지된다.
- @Component를 사용하는 경우
- 컨트롤러, 서비스, 리포지토리가 모두 아니고, 개발자가 직접 작성한 클래스를 스프링 빈으로 등록할 때 사용된다.
-
스프링 빈을 가져오는 방법
- 생성자를 이용해 주입받는 방식
- setter와 @Autowired 사용 누군가 setter를 사용하면 오작동 할 수 있다.
- 필드에 직접 @Autowired 사용 테스트를 어렵게 만드는 요인이다.
-
@Qualifier : 여러 개의 클래스 후보군이 있을때 그 중 특정 클래스를 가져오고 싶은 경우 사용하는 어노테이션
-
스프링 빈을 사용하는 쪽, 등록하는 쪽 모두 @Qualifier를 사용할 수 있다.
-
스프링 빈을 사용하는 쪽에서만 쓰면, 빈의 이름을 적어주어야 한다.
-
양쪽 모두 사용하면, @Qualifier끼리 연결된다.
- @Primary 와 @Qualifier 중 우선 순위는? 사용하는 쪽에서 직접 적어준 @Qualifier가 우선한다.
Section 3 정리
- 스프링 컨테이너와 스프링 빈이 무엇인지 이해함.
- 스프링 컨테이너가 왜 필요한지, 좋은 코드와 어떻게 연관이 있는지 이해함.
- 스프링 빈을 다루는 여러 방법을 이해함.
섹션 4 생애 최초 JPA 사용하기
문자열 SQL을 직접 사용하는 것이 너무 어렵다
-
SQL을 직접 작성하면 나타나는 문제점
- 문자열을 작성하기 때문에 실수할 수 있고, 실수를 인지하는 시점이 느리다. (컴파일 시점에 발견되지 않고, 런타임 시점에 발견된다.)
- 특정 데이터베이스에 종속적이게 된다.
- 반복 작업이 많아진다. 테이블을 하나 만들 때마다 CRUD 쿼리가 항상 필요하다.
- 데이터베이스의 테이블과 객체는 패러다임이 다르다.
-
JPA (Java Persistence API) : 객체와 관계형 DB의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java 진영의 규칙
-
JPA는 규칙일 뿐이고, 규칙을 실제로 구현한 건 HIBERNATE이며 HIBERNATE 는 내부적으로 JDBC를 사용한다.
-
JPA를 활용해 매핑하는 것 다음 시간에
유저 테이블에 대응되는 Entity Class 만들기
-
Java객체와 MySQL 테이블을 매핑.
-
@Entity : 스프링이 User객체와 user테이블을 같은 것으로 바라보게한다.
-
@Id : 이 필드를 primary key로 간주한다.
-
@GeneratedValue : primary key는 자동 생성되는 값이다.
-
JPA를 사용하기 위해서는 기본 생성자가 꼭 필요하다.
-
@Column : 객체의 필드와 테이블의 필드를 매핑한다. null의 여부, 길이 제한, DB의 Column 이름 등을 정의한다. 단 객체의 필드와 테이블의 필드가 동일한 경우 생략할 수 있다.
-
JPA를 사용하기 위한 추가적인 설정
application.yml
jpa:
hibernate:
ddl-auto: none // 스프링이 시작할 때 DB에 있는 테이블을 어떻게 처리할지 설정.
// create : 기존 테이블이 있다면 삭제 후 다시 생성
// create-drop : 스프링이 종료될 때 테이블을 모두 제거
// update : 객체와 테이블이 다른 부분만 변경
// validate : 객체와 테이블이 동일한지 확인
// none : 별다른 조치를 하지 않는다.
properties:
hibernate:
show_sql: true // JPA를 사용해 DB에 SQL을 날릴 때 SQL을 보여줄지 말지.
format_sql: true // SQL을 보여줄 때 이쁘게 포맷팅 할지 말지.
dialect: org.hibernate.dialect.MySQL8Dialect // 이 옵션으로 DB를 특정하면 조금씩 다른 SQL을 수정해준다.
Spring Data JPA를 이용해 자동으로 쿼리 날리기
-
SQL을 작성하지 않고, 유저 생성 / 조회 / 업데이트 기능을 리팩토링하기.
-
UserRepository 인터페이스 생성
-
UserRepository 인터페이스는 JpaRepository를 상속 받음
-
유저 저장 기능 : save 메소드에 객체를 넣어주면 INSERT SQL이 자동으로 날라가게끔 한다.
-
유저 조회 기능 : findAll을 사용해 모든 데이터를 가져오도록 한다.
-
유저 업데이트 기능 : id를 이용해 User를 가져와 User의 유,무를 확인하고, User가 있으면 update 쿼리를 달려 데이터를 수정한다.
-
-
사용한 기능
- save : 주어지는 객체를 저장하거나 업데이트 시켜준다.
- findAll : 주어지는 객체가 매핑된 테이블의 모든 데이터를 가져온다.
- findById : id를 기준으로 특정한 1개의 데이터를 가져온다.
-
Spring Data JPA : 복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리
Spring Data JPA를 이용해 다양한 쿼리 작성하기
-
삭제 기능을 Spring Data JPA로 변경하기.
-
Spring Data JPA를 활용해 조회 쿼리를 작성하는 방법
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByName(String name);
}
- 반환 타입을 User로, 유저가 없으면 null이 반환되도록 한다.
- 함수 이름만 작성하면, 알아서 SQL이 조립된다.
- find라고 작성하면, 1개의 데이터만 가져온다.
- By 뒤에 붙는 필드 이름으로 SELECT 쿼리의 WEHRE문이 작성된다.
- SELECT * FROM user WHERE name = ?;
public void deleteUser(String name) {
User user = userRepository.findByName(name)
.orElseThrow(IllegalArgumentException::new);
userRepository.delete(user);
}
- 주어지는 데이터를 DB에서 제거한다.
-
DELETE SQL;
-
다양한 Spring Data JPA 쿼리
-
By 앞에 들어갈 수 있는 구절
-
find : 1건을 가져온다. 반환 타입은 객체 또는 Optional<타입>이 될 수 있다.타입>
-
findAll : 쿼리의 결과물이 N개인 경우 사용한다. List<타입> 을 반환한다.타입>
-
exists : 쿼리 결과가 존재하는지 확인한다. Boolean 타입으로 반환한다.
-
count : SQL의 결과 개수를 센다. Long타입으로 반환한다.
-
-
By 뒤에 들어갈 수 있는 구절 (AND, OR로 조합 가능)
-
GreaterThan : 초과
-
GreaterThanEqual : 이상
-
LessThan : 미만
-
LessThanEqual : 이하
-
Between : 사이에
-
StartsWith : ~로 시작하는
-
EndsWith : ~로 끝나는
-
트랜잭션에 대해 다음 시간에
트랜잭션 이론편
-
트랜잭션 : 쪼갤 수 없는 업무의 최소 단위 모두 다 성공시키거나 모두 다 실패시키거나 하기 위한 것.
-
트랜잭션 시작 : start transaction;
-
트랜잭션 종료 : commit;
-
트랜잭션 실패 처리 : rollback;
-
-
트랜잭션을 통해 하나의 함수에서 여러 개의 Insert 쿼리 중 모두 성공하면 반영하고, 하나라도 실패하면 반영이 안되도록 할 수 있다.
트랜잭션 적용과 영속성 컨테스트
-
서비스 메소드가 시작할 때 트랜잭션이 시작된다.
-
서비스 메소드 로직이 모두 정상적으로 성공하면 commit이 된다.
-
서비스 메소드 로직 실행 도중 문제가 생기면 rollback 되도록 한다.
-
@Transactional 으로 간단하게 적용 가능하다.
-
조회만 하는 SQL의 경우 @Transactional(readOnly = true) 로 읽기만 가능하도록 할 수 있다.
-
IOException과 같은 Checked Exception은 롤백이 일어나지 않는다.
-
영속성 컨텍스트 : 테이블과 매핑된 Entity 객체를 관리/보관하는 역할
-
스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생겨나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다.
-
영속성 컨텍스트의 특수 능력 4가지
- 변경 감지 (Dirty Check) : 영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save하지 않더라도, 변경을 감지해 자동으로 저장된다.
- 쓰기 지연 : DB의 INSERT / UPDATE / DELETE SQL을 바로 날리는 것이 아니라, 트랜잭션이 commit될 때 모아서 한 번만 날린다.
- 1차 캐싱 : ID를 기준으로 Entity를 기억하고, 캐싱된 객체는 완전히 동일하다.
Section 4 정리
- 문자열 SQL을 직접 사용하는 것의 한계를 이해하고, 해결책인 JPA, Hibernate, Spring Data JPA가 무엇인지 이해한다.
- Spring Data JPA를 이용해 데이터를 생성, 조회, 수정, 삭제할 수 있다.
- 트랜잭션이 왜 필요한지 이해하고, 스프링에서 트랜잭션을 제어하는 방법을 익힌다.
- 영속성 컨텍스트와 트랜잭션의 관계를 이해하고, 영속성 컨텍스트의 특징을 알아본다.
섹션 5 책 요구사항 구현하기
책 생성 API 개발하기
-
요구사항 : 도서관에 책을 등록할 수 있다.
-
API 스펙
- HTTP Method : POST
- HTTP Path : /book
- HTTP Body (JSON) :
{ "name": String //책 이름 }
- 결과 반환 : 상태코드 200
대출 기능 개발하기
-
요구사항 : 사용자가 책을 빌릴 수 있다. 단 다른 사람이 그 책을 빌렸다면, 빌릴 수 없다.
-
API 스펙
- HTTP Method : POST
- HTTP Path : /book/loan
- HTTP Body (JSON) :
{ "userName": String "bookName": String }
- 결과 반환 : 상태코드 200
반납 기능 개발하기
-
요구사항 : 사용자가 책을 반납할 수 있다.
-
API 스펙
- HTTP Method : POST
- HTTP Path : /book/return
- HTTP Body (JSON) :
{ "userName": String "bookName": String }
-
결과 반환 : 상태코드 200
-
지금 까지 작성한 코드를 조금 더 객체지향적으로 만드는 방법
- User와 UserLoanHistory가 직접 협업할 수 있게 처리하는 방법 다음 강의에서
Section 5 정리
- 책 생성, 대출 반납 API를 온전히 개발하며 지금까지 다루었던 모든 개념을 실습해 봤다.
2주차 과제
과제 4번 : https://www.inflearn.com/blogs/7855
- 과일 정보를 저장하는 API 만들기
- API에서 long을 사용한 이유
- 팔린 과일 정보를 기록하는 API 만들기
- 특정 과일을 기준으로 팔린 금액, 팔리지 않은 금액을 조회하는 API 만들기
- sum, group by 키워드를 사용해 구현해보기
과제 5번 : https://www.inflearn.com/blogs/7873
- 제시된 주사위 코드를 클린 코드로 변환해보기
- 숫자 범위가 달라지더라도 동작되도록 변환해보기
2주차 후기
지난주 1주차 회고록에 이어서 벌써, 인프런 워밍업 클럽 과정의 2주차가 마무리됬다. 이번 주차에서는 섹션 3의 일부분 부터 섹션 5의 일부분의 강의를 수강할 수 있었다. 간단하게 각 섹션 별로 강의의 주제를 다시한번 상기하고 어떤걸 배우고 느꼈는지 확인해보려고 한다.
섹션 3의 주제 : 역할의 분리와 스프링 컨테이너 역할의 분리에 대해서는 이전 회고록에서 상세히 다루었기 때문에 다루지 않겠다.
섹션 4의 주제 : 생애 최초 JPA 사용하기 문자열 SQL을 직접 사용하는 것의 한계를 이해하고, 해결책인 JPA, Hibernate, Spring Data JPA가 무엇인지 이해할 수 있었다. Spring Data JPA를 이용해 데이터를 생성, 조회, 수정, 삭제해 볼 수 있었다. 트랜잭션이 왜 필요한지 이해하고, 스프링에서 트랜잭션을 제어하는 방법을 익혔다. 영속성 컨텍스트와 트랜잭션의 관계와 특징을 이해할 수 있었다.
섹션 5의 주제 : 책 요구사항 구현하기 책 생성, 대출 반납 API를 온전히 개발하며 지금까지 다루었던 모든 개념을 실습해 볼 수 있었다.
깜작 라이브 강의
5번 과제인 클린 코드로 변환하는 방법에 대해 깜짝 라이브 강의를 열어 자세한 코드 리뷰를 진행했다.
강의를 보며 크게 느낀점이 항상 클린 코드를 만든다고 만들지만 그 끝은 끝이 없구나 하고 생각이 들었다.
마무리
이번 2주차 강의를 듣고 회고록을 작성하면서 앞으로도 지금처럼 성실함을 중점으로 꾸준하게 강의를 듣고 기록하는 것이 중요하다고 생각했다. 다음주는 벌써 배포에 대해 배우는 시점이 온다. 개인적으로 제일 관심이 있던 부분이기 때문에 더 확실하게 이해하기 위해 주말에 미리 선행을 좀 해보려고 한다.
댓글남기기