![[인프런 워밍업 클럽 1기/BE] 두번째 발자국](https://cdn.inflearn.com/public/files/blogs/f1379a1c-9fbb-44a5-9b94-e2ffbd1eb82d/썸네일.png)
[인프런 워밍업 클럽 1기/BE] 두번째 발자국
2주차 발자국을 찍으며..
생각보다 시간을 잘 활용하지 못한 것 같다.
이 강의를 들으며, 잊었던 자바8 이후 문법들에 대해서도 익숙해지도록 공부하려고 마음 먹었으나 급한 일이 겹치고 오늘만은 늦더라도 강의 듣고 공부 더 하고 자야지 했던 다짐이 조금 무너졌었다.
다음주는 꼭 강의와 과제는 일찍 챙겨 듣고 추가 공부를 더 해서 많이 남겨보는 게 목표이다.
아 그리고 월요일(한 주의 시작)에 그 주의 계획을 세워보고 그대로 살아보기 또한 목표이다.
섹션4. 생애 최초 JPA 사용하기
Spring Data JPA를 사용한 데이터베이스 조작. 23~26강
SQL 사람이 직접 작성하면 아쉬운 점
에러가 컴파일 시점(서버를 실행하는 그 순간. .java → .class로 변환시켜서 jvm에서 동작시키는 과정)에 발견되지 않고, 런타임 시점(실제 서버가 동작하고 나서)에 발견된다.
특정 데이터베이스에 종속적이게 된다
반복 작업이 많아진다. 테이블 하나 만들 때마다 CRUD 쿼리가 필요.
DB의 테이블과 객체는 패러다임이 다르다.
객체에선 교실과 학생은 서로를 가리킬 수 있다.
DB에선 학생만 교실을 가리킨다.
상속관계는 DB 테이블로 표현하기 어렵다
요즘은 어플리케이션을 객체지향적인 설계를 지향. DB 테이블을 직접 쓰기가 애매함
그래서 등장하게 된 것이 JPA(Java Persistence API)
자바 진영의 ORM(Object-Relational Mapping)
영속성 : 서버가 재시작되어도 데이터는 영구적으로 저장되는 속성
객체와 관계형 DB의 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 JAVA 진영의 규칙
말로 되어 있는 규칙을 코드로 구현 → 그 코드가 HIBERNATE(JPA를 구현하는 구현체)
Hibernate는 내부적으로 JDBC를 사용한다.
Java 객체와 MySQL 테이블 매핑
@Entity : 스프링이 User객체와 user 테이블을 같은 것으로 바라본다.
Entity의 의미는 저장되고, 관리되어야 하는 데이터객체엔 없었던 id 필드를 추가해준다.
@Id
: 이 필드를 primary key로 간주한다.@GeneratedValue(strategy = GenerationType.*IDENTITY*)
(MySQL의 Auto_Increment와 동일. primary key는 자동생성되는 값이다.)
※ DB마다 자동 생성 전략이 다르다고 함JPA를 사용하려면 Entity 객체에는 기본생성자(매개변수가 없는)가 필수임. protected로 해도 됨
@Column : 객체의 필드와 Table의 필드를 매핑한다. 여러 DB의 설정을 연결함
ex)
@Column(nullable = false, length = 20, name = "name")
필드의 이름도 name이고 DB의 컬럼 이름도 name이므로 생략가능. 필드의 이름이 다를 때 연결시켜줄 때 사용하기도 함
필드가 컬럼과 동일할 경우 @Column 어노테이션을 생략할 수 있다.
JPA를 사용하려면 application.yml 파일에 아래와 같이 추가가 필요하다
ddl-auto : 스프링이 시작할 때 DB에 있는 테이블을 어떻게 처리할지
DB와 객체가 서로 다르게 생겼으면 검증할 수도 있고, 무시할 수도 있고, 테이블을 바꿀 수도 있음
create : 기존 테이블이 있다면 삭제 후 다시 생성(들어있는 데이터 삭제됨)
create-drop : 스프링이 종료될 때 테이블을 모두 제거(들어있는 데이터 삭제됨)
update : 객체와 테이블이 다른 부분만 변경
validate : 객체와 테이블이 동일한지 확인(실패하면 서버를 종료시킴)
none : 별다른 조치를 하지 않는다.
show_sql : JPA를 사용해 DB에 SQL을 날릴 때 SQL을 보여줄 것인가
format_sql : SQL을 보여줄 때 예쁘게 포맷팅할 것인가
dialect(방언,사투리) : 이 옵션으로 DB를 특정하면 조금씩 다른 SQL을 수정해준다.
public interface UserRepository extends JpaRepository<User, Long> {
}
domain에 user 옆에 UserRepository 인터페이스를 하나 만든다.
이후 JpaRepository를 상속받고 <> 안에 Entity 객체, User의 id 타입을 적어주면 된다이 인터페이스는 @Repository를 붙이지 않아도 JpaRepository를 상속받는 것만으로 Spring bean으로 관리된다.
저 인터페이스의
save 메소드
에 객체를 넣어주면 INSERT SQL이 자동으로 날아간다.save되고 난 후의 User에는
id
가 들어있다.해당 인터페이스의
findAll 메소드
를 사용하면 모든 데이터를 가져온다.(select * from user)
위와 같이 작성해주면(객체를 업데이트 해주고나서 save 메소드를 호출)
마지막에 save할 때 변경사항이 있으면 자동으로 바뀐 객체정보로 update문이 날아가게 됨
SQL을 작성하지 않아도 동작하는 이유
Spring Data JPA : 복잡한 JPA 코드를 스프링과 함께 쉽게 사용할 수 있도록 도와주는 라이브러리
SimpleJpaRepository : 어려운 JPA코드를 감싼 라이브러리(사용자가 쉽게 쓸 수 있게)
다양한 쿼리를 Spring Data JPA로 변경해보자
userRepository.delete(user); 로 데이터를 DB에서 제거하게 됨
기본 제공되지 않는 메서드 만드는 법
함수 이름이 중요함. 알아서 SQL이 조립됨.
find라고 작성하면, 1개의 데이터만 가져온다.
By 뒤에 붙는 필드 이름으로 SELECT 쿼리의 WHERE문이 작성된다.
By 뒤에 올 수 있는 구절
트랜잭션과 영속성 컨텍스트(27~29강)
저번시간까지는 Repository 계층이 하는 일 처리,
이제는 Service 계층이 해야하는 추가적인 역할인 transaction에 대해 알아보자
트랜잭션
쪼갤 수 없는 업무의 최소 단위
모든 SQL을 성공시키거나, 하나라도 실패하면 모두 실패시키자
트랜잭션 명령어
시작 : start transaction;
정상 종료 : commit;
실패처리 : rollback;
※ 트랜잭션을 시작했을 때 commit 전 데이터를 다른 접속에서도 보이게 할 수는 있다(옵션조절로)
하지만 대부분 그러지 않는 기본값을 사용함트랜 잭션 적용 방법
@Transactional 어노테이션 사용
함수에 붙이면 함수가 시작될 때 트랜잭션이 시작되고 함수가 종료될 때
commit(정상종료시)/rollback(에러발생시)을 해주도록 적용SELECT 쿼리만 사용한다면, (readOnly = true) 옵션을 붙일 수 있다.
저장, 업데이트, 삭제 등 데이터 변경을 위한 불필요한 기능이 빠져서 약간의 성능적 이점이 있음
Service 계층의 중요한 역할 : 비즈니스 로직을 가지고 있는 것, 여러 SQL에 접속해야할 경우 트랜잭션 관리
※ 주의사항 : IOException 같은 Checked Exception은 롤백이 일어나지 않는다.
(서비스계층에서 날 일은 거의 없긴 하다)영속성 컨텍스트 : 테이블과 매핑된 Entity 객체를 관리/보관하는 역할
스프링에서는 트랜잭션을 사용하면 영속성 컨텍스트가 생겨나고, 트랜잭션이 종료되면 영속성 컨텍스트가 종료된다.
영속성 컨텍스트의 특수 능력 4가지
변경 감지(Dirty Check) : 영속성 컨텍스트 안에서 불러와진 Entity는 명시적으로 save하지 않더라도,
변경을 감지해 자동으로 저장된다. ⇒ updateUser 함수에서 userRepository.save를 지워도 자동으로 저장됨쓰기 지연 : 영속성 컨텍스트 안에서 DB INSERT/UPDATE/DELETE SQL을 바로 날리는 것이 아니라,
트랜잭션이 commit될 때 모아서 한 번만 날린다.(통신횟수 줄고 비용이 줄어듬)1차 캐싱 : ID를 기준으로 Entity를 기억한다(통신횟수 줄고 비용이 줄어듬),
이렇게 캐싱된 객체는 완전히 동일하다(자바의 같은 객체. 주소가 같은 객체와 같은 의미)나머지 하나는 다음 섹션에서….!
과제4. 추가적인 API를 만들어 보며 API 개발에 익숙해지기
https://slime-feels-660.notion.site/60da5bdb68b9456cad02df9659fff823?pvs=4
4-1은 강의 때 배운대로 3단계의 layer로 분리하여 코드를 작성하였고 자바의 LocalDate를 MySQL의 date 형식과 맞춰 작업하면 되겠구나 생각한 것 외에는 간단했던 것 같다.
4-2는 테이블을 변경하는 DDL을 검색해서 풀었다. 잠시 까먹었던 문법을 상기시킬 수 있었다.
4-3은 문제가 제시하는 형태로 API 결과값을 만들어야 해서 SQL을 두 번 보내는 방식으로 할 지,
SQL문 자체를 group by / sum 을 사용해서 후처리를 할 지 고민하다가 두번째 방법을 쓰고 최대한 배운대로 작업해보고자 노력해서 조금 시간이 더 걸렸다. 잊었던 SQL들을 공부한 느낌이라 역시 계속 한 번씩이라도 다시 봐야겠다고 생각했다.
<추가> 자바에서 정수를 다루는 가장 대표적인 두 가지 방법은 int 와 long 입니다.
이 두 가지 방법 중 위 API에서 long 을 사용한 이유는 무엇일까요?
나도 비슷하게 답변을 하였지만, 실제 면접에서 답변하듯이 깔끔한 대답은 잘 못 한 것 같다.
값이 커질 수 있다는 말만 하였고 오버플로우가 발생할 수 있다는 식의 대답은 하지 못한 것 같아 조금 더 이런 질문에
면접에서의 원하는 깔끔한 대답을 할 수 있도록 준비해야 겠다고 생각이 들었다.
+) 4번 과제.. 날짜를 착각해서 제출이 조금 늦어졌지만 새벽에 끝까지 집중해서 과제를 마무리하고 제출 후 잠들어 그나마 마음의 짐이 덜어진 것 같았고, 꼼꼼히 과제 체크 및 강의 듣는 것을 다시 한 번 다짐했다..
과제5. 주어진 코드를 클린 코드로 고쳐보기
https://slime-feels-660.notion.site/ba498281917f439b8f230cb8f87ac29b?pvs=4
인터넷 검색을 해보며 클린 코드에 대해 다시 한 번 생각해보게 되었고, 모듈화 하는 것을 나는 솔직히 코딩작업 시간을 늘리고 굳이 이렇게까지 나눠야 하나 라는 생각이 더 컸었다. 그런데 생각을 해보니, 나만 볼 때야 다 알아볼 수 있으니까 그런거지라는 생각이 들었고 코드를 깔끔하게 작업한다면 함께 일하는 사람들이 볼 때 훨씬 편하겠다는 생각을 하게 되었다.
여태까지 나와 함께 프로젝트를 했던 사람들은 그럼 힘들었을까? 라는 생각을 해보며 최대한 모듈화, 함수명 네이밍, 주석 등을 신경쓰며 과제를 진행하였다.
마무리
2주차가 벌써 지나갔다. 시간이 참 빠른 것 같다. 아직 공부하고 싶은 것도 많고 해야할 것도 많다고 생각한다.
절대 나태해지지 말고 강의 꾸준히, 쉬는 시간 적당히, 적절한 운동으로 건강까지..
모두 챙겨서 3주차엔 행복하게 발자국을 남길 수 있길 바래본다.
댓글을 작성해보세요.