✏️ 0517
Spring 개인 과제
수준별 학습: 스탠다드 실습반
Spring 입문_2주차
하이버네이트 ( Hibernate )
자바 언어를 위한 ORM 프레임워크,
데이터베이스에 저장된 데이터와 프로그램의 객체를 매핑하는 기술 중 하나
JPA 의 구현체로, JPA 인터페이스를 구현하고, 내부적으로 JDBC API 사용
Hibernate 기반으로 만들어진 ORM 기술 표준이 JPA 이다
영속성 컨텍스트
Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간
1차 캐시
영속성 컨텍스트는 내부적으로 캐시 저장소를 가지고 있다
우리가 저장하는 Entity 객체들이 1차 캐시( 캐시 저장소 )에 저장된다고 생각하면 된다
캐시 저장소는 Map 자료구조 형태
key 에는 @Id 로 매핑한 기본 키, 식별자 값을 저장
value 에는 해당 Entity 클래스의 객체를 저장
영속성 컨텍스트는 캐시 저장소 Key 에 저장한 식별자값을 사용하여 Entity 객체를 구분하고 관리
- 장점
- DB 조회 횟수를 줄일 수 있다
- 1차 캐시를 사용해 DB row 1개 당 객체 1개가 사용되는 것을 보장
- 객체 동일성 보장
쓰기 지연 저장소(ActionQueue)
JPA 가 트랜잭션처럼 SQL 을 모아서 한번에 DB 에 반영해준다
이를 구현하기 위해서 쓰기 지연 저장소를 만들어 SQL 을 모아두고 있다가
트랜잭션 commit 후 한번에 DB 에 반영
flush()
영속성 컨텍스트의 변경 내용들을 DB에 반영하는 역할을 수행
=> 쓰기 지연 저장소의 SQL들을 DB에 요청하는 역할을 수행
변경 감지(Dirty Checking)
JPA는 영속성 컨텍스트에 Entity를 저장할 때 최초 상태(LoadedState)를 저장
트랜잭션이 commit 되고 em.flush(); 가 호출되면 Entity 의 현재 상태와 저장한 최초 상태를 비교한다
변경 내용이 있다면 Update SQL을 생성하여 쓰기 지연 저장소에 저장하고 모든 쓰기지연 저장소의 SQL을 DB에 요청
마지막으로 DB 의 트랜잭션이 commit 되면서 반영된다
변경하고 싶은 데이터가 있다면 먼저 데이터를 조회하고
해당 Entity 객체의 데이터를 변경하면 자동으로 Update SQL이 생성되고 DB에 반영
=> 이런 과정을 변경 감지, Dirty Checking 이라 부른다
SpringBoot의 JPA
SpringBoot 환경에서는 EntityManagerFactory와 EntityManager를 자동으로 생성해준다
application.properties에 DB 정보를 전달해 주면 이를 토대로 EntityManagerFactory가 생성
@PersistenceContext
EntityManager em;
@PersistenceConext 애너테이션을 사용하면 자동으로 생성된 EntityManager를 주입받아 사용할 수 있다
Spring의 트랜잭션
Spring 프레임워크에서는 DB의 트랜잭션 개념을 애플리케이션에 적용할 수 있도록 트랜잭션 관리자를 제공
@Transactional 애너테이션을 클래스나 메서드에 추가하면 쉽게 트랜잭션 개념을 적용 가능
@Test
@Transactional
// 테스트 코드에서 @Transactional 를 사용하면
// 테스트가 완료된 후 롤백하기 때문에 false 옵션 추가
@Rollback(value = false)
@DisplayName("메모 생성 성공")
void test1() {
Memo memo = new Memo();
memo.setUsername("Robbert");
memo.setContents("@Transactional 테스트 중!");
em.persist(memo); // 영속성 컨텍스트에 메모 Entity 객체를 저장합니다.
}
JPA를 사용하여 DB에 데이터를 저장, 수정, 삭제 하려면 트랜잭션 적용이 반드시 필요
조회 작업은 단순하게 데이터를 읽기만 하기 때문에 트랜잭션 적용이 필수는 아니다
조회의 경우에도 트랜잭션 환경이 필요한 경우가 있을 수 있기 때문에
조회 작업 기능만 존재하는 메서드일 경우에만
readOnly = true 옵션이 설정된 @Transactional을 적용하면 좋다
Spring Data JPA
JPA를 쉽게 사용할 수 있게 만들어놓은 하나의 모듈
JPA를 추상화시킨 Repository 인터페이스를 제공
Spring Data JPA의 SimpleJpaRepository
public interface MemoRepository extends JpaRepository<Memo, Long> { }
JpaRepository 인터페이스를 구현하는 클래스를 자동으로 생성
pring 서버가 뜰 때 JpaRepository 인터페이스를 상속받은 인터페이스가 자동으로 스캔이 되면,
해당 인터페이스의 정보를 토대로 자동으로 SimpleJpaRepository 클래스를 생성해 주고,
해당 클래스를 Spring ‘Bean’으로 등록한다
따라서 인터페이스의 구현 클래스를 직접 작성하지 않아도
JpaRepository 인터페이스를 통해 JPA의 기능을 사용할 수 있다
JPA 짱이네...
JDBC 만 써봐서 이런게 있는줄 몰랐따...
JPA Auditing
Timestamped
데이터의 생성(created_at), 수정(modified_at) 시간은 포스팅, 게시글, 댓글 등 다양한 데이터에 매우 자주 활용
각각의 Entity의 생성 수정 시간을 매번 작성하는건 너무 비효율적이다
그리고 힘들고 귀찮다
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAt;
@LastModifiedDate
@Column
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime modifiedAt;
}
Spring Data JPA에서는 시간에 대해서 자동으로 값을 넣어주는 기능인 JPA Auditing을 제공
- @MappedSuperclass
- JPA Entity 클래스들이 해당 추상 클래스를 상속할 경우
createdAt, modifiedAt 처럼 추상 클래스에 선언한 멤버 변수를 컬럼으로 인식할 수 있다
- JPA Entity 클래스들이 해당 추상 클래스를 상속할 경우
- @EntityListeners(AuditingEntityListener.class)
- 해당 클래스에 Auditing 기능을 포함
- @CreatedDate
- Entity 객체가 생성되어 저장될 때 시간이 자동으로 저장
- 최초 생성 시간이 저장되고 그 이후에는 수정되면 안되기 때문에 updatable = false 옵션을 추가
- @LastModifiedDate
- 조회한 Entity 객체의 값을 변경할 때 변경된 시간이 자동으로 저장
- 처음 생성 시간이 저장된 이후 변경이 일어날 때마다 해당 변경시간으로 업데이트
- @Temporal
- 날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용
- DB에는 Date(날짜), Time(시간), Timestamp(날짜와 시간)라는 세 가지 타입 존재
- DATE : ex) 2023-01-01
- TIME : ex) 20:21:14
- TIMESTAMP : ex) 2023-01-01 20:22:38.771000
⭐JPA Auditing 기능을 사용하겠다는 정보를 전달해주기 위해
@SpringBootApplication 이 있는 class에 @EnableJpaAuditing 추가!⭐
Query Methods
Spring Data JPA에서는 메서드 이름으로 SQL을 생성할 수 있는 Query Methods 기능을 제공
public interface MemoRepository extends JpaRepository<Memo, Long> {
// 수정 시간을 기준으로 전체 데이터를
// 내림차순으로 가져오는 SQL을 실행하는 메서드 생성
List<Memo> findAllByOrderByModifiedAtDesc();
// ByUsername 에 값을 전달해줘야하기 때문에
// 파라미터에 해당 값의 타입과 변수명 선언
// 파라미터를 통해 SQL에 필요한 값을 동적으로 받아 처리
List<Memo> findAllByContentsContainsOrderByModifiedAtDesc(String keyword);
}
JpaRepository 인터페이스에서 해당 인터페이스와 매핑되어있는 테이블에 요청하고자하는
SQL을 메서드 이름을 사용하여 선언할 수 있다
SimpleJpaRepository 클래스가 생성될 때 위처럼
직접 선언한 JpaRepository 인터페이스의 모든 메서드를 자동으로 구현해준다
public List<MemoResponseDto> getMemos() {
// DB 조회
return memoRepository.findAllByOrderByModifiedAtDesc()
.stream()
.map(MemoResponseDto::new).toList();
}
ex) 최신 메모가 가장 상단에 나올 수 있도록
회고
Been 이라던가... 영속성이라던가...
아무튼 이것저것 2주차 강의라던가.... 너무 어렵다😵😵
정리하면서 한번 더 보고 조금 이해되는 것도 있지만
여전히 헷갈리는 것도 마찬가지..ㅜ
더 천천히 보고 싶었는데 과제도 해야해서 시간이 너무 부족했던 것 같다 ToT
'개발 일지 > TIL' 카테고리의 다른 글
[ #25 ] TIL (0) | 2024.05.21 |
---|---|
[ #24 ] TIL (2) | 2024.05.20 |
[ #22 ] TIL (1) | 2024.05.17 |
[ #21 ] TIL (2) | 2024.05.14 |
[ #20 ] TIL (4) | 2024.05.13 |