스프링부트 너 뭐 돼?🤷‍♀️(7) - 영속성 컨텍스트, JPA의 활용

joyfulwave·2022년 12월 5일
0

피할 수 없다면 즐기자! 스프링부트 너.. 뭐 돼?




📚 JPQL

Java Persistence Query Language

  • JPA를 사용하면 객체를 중심으로 개발할 수 있어요.
  • 하지만 검색 쿼리(select)에서는 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능해요. 그래서 검색 조건이 포함된 SQL이 필요해졌어요.
  • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공해요. 기존 SQL과 문법이 유사하며 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN등을 지원해요.

⚫ SQL : 데이터베이스 테이블을 대상으로 쿼리를 작성

⚫ JPQL : 객체를 대상으로 쿼리를 작성




📚 JPA 실습 환경 세팅

📌 spring boot 프로젝트 생성

⚫ (1)

아래의 url에 접속하여 자신의 환경 세팅대로 선택한 후 "spring Data JPA" 과 "Oracle Driver", "Lombok" dependencies를 추가해주세요. 다 세팅 후 하단의 generate를 클릭하여 다운받아주세요.

https://start.spring.io/

⚫ (2)

프로젝트 import 이후에 과정 다음 블로그 참고.
https://velog.io/@luvjoyyy/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EB%84%88-%EB%AD%90-%EB%8F%BC1-SPRING-BOOT

⚫ (3)

[src/main/resources]에 [META-INF] 폴더를 생성 후 [persistence.xml] 파일을 생성해줘요.

⚫ (4)

해당 파일에 속성을 입력해주세요.

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.2"
	xmlns="http://xmlns.jcp.org/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
	<persistence-unit name="hello">
		<properties>
			<!-- 필수 속성 -->
			<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver" />
			<property name="javax.persistence.jdbc.user" value="springjpa" />
			<property name="javax.persistence.jdbc.password" value="springjpa" />
			<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<!-- 			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL10Dialect" /> -->


			<!-- 
				실제 서버 배포시에는 없애주는게 좋다. 실습 때 다양한 테이블 생성을 위한 것 
				코드 작성에 따라 자동으로 테이블 삭제와 생성을 담당한다.
			-->
			<property name="hibernate.hbm2ddl.auto" value="create" />

			<!-- 옵션 -->
			<!-- 콘솔에 하이버네이트가 실행하는 SQL문 출력 -->
			<property name="hibernate.show_sql" value="true" />
			<!-- SQL 출력 시 보기 쉽게 정렬 -->
			<property name="hibernate.format_sql" value="true" />
			<!-- 쿼리 출력 시 주석(comments)도 함께 출력 -->
			<property name="hibernate.use_sql_comments" value="true" />
		</properties>
	</persistence-unit>
</persistence>



📚 영속성 컨텍스트

  • JPA를 이해하는데 가장 중요한 용어로 객체의 엔티티를 영구 저장하는 환경이라는 의미를 가져요.

EntityManager.persist(entity);

  • "entity"에 들어가는 객체(Member, Team, .. 등)를 DB에 단순히 저장하는 의미보다는 더 큰 의미를 가지게 돼요. EntityManager.persist(entity); 를 작성하면 처음부터 DB에 저장하는게 아니라 영속성 컨텍스트 라는 곳에 저장하게 되는데 엔티티 매니저를 통해서 영속성 컨텍스트에 접근할 수 있어요.

📌 엔티티 생명주기

  • 비영속(new/transient)
    : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
  • 영속(managed)
    : 영속성 컨텍스트에 관리되는 상태
  • 준영속(datached)
    : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제(removed)
    : 삭제된 상태

⚫ 비영속

Member member = new Member();
member.setId("userA");
member.setName("회원1");

⚫ 영속

em.persist(member);

⚫ 준영속

em.detach(member);

⚫ 삭제

em.remove(member);

📌 영속성 컨텍스트의 이점

  • 1차 캐시
  • 동일성 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경감지(Dirty Checking)
  • 지연 로딩(Lazy Loading)

⚫ 엔티티 조회, 1차 캐시

Member member = new Member();
member.setId("member1");
member.setName("회원1");

em.persist(member);

// 조회
Member findMember = em.find(Member.class, "member1");

⚫ 데이터베이스에서 조회

Member member = new Member();
member.setId("member1");
member.setName("회원1");

em.persist(member);

// 조회
Member findMember = em.find(Member.class, "member1");
Member findMember2 = em.find(Member.class, "member2");

⚫ 영속 엔티티의 동일성 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");

⚫ 엔티티 등록 트랜잭션을 지원하는 쓰기 지연


tx.begin();	// 트랜잭션 시작

em.persist(memberA);
em.persist(memberB);
// 여기까지는 insert sql을 데이터베이스에 보내지 않는다.

// 커밋하는 순간 데이터베이스에 insert sql을 보낸다.
tx.commit();	// 트랜잭션 커밋

⚫ 엔티티 수정 변경 감지(Dirty Checking)

  • flush()가 호출되는 시점에 Entity와 스냅샷을 전부 비교 후, 변경이 된 것을 감지(Dirty Checking)한 후에 update쿼리를 작성 후, update쿼리를 보내줘요.
tx.begin();	// 트랜젝션 시작

// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");

memberA.setUsername("hello");
memberA.setAge(10);

// em.update(member) => 존재하지않음.


tx.commit();	// 커밋

⚫ 엔티티 삭제

// 삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, "memberA");

em.remove(memberA); // 엔티티 삭제

📌 플러시(flush)

  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영

⚫ 플러시 발생

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL저장소에 등록
  • 쓰기 지연 SQL저장소의 쿼리를 데이터베이스에 전송

⚫ 영속성 컨텍스트를 플러시하는 방법

  • em.flush() : 직접 호출
  • 트랜잭션 커밋 : 플러시 자동 호출
  • JPQL 쿼리 실행 : 플러시 자동 호출

📌 준영속 상태

  • 준영속 : 영속 상태의 엔티티가 영속성 컨텍스트에서 분리가 되는 것을 의미해요. (detached)
  • 영속성 컨텍스트가 제공하는 기능을 사용하지 못해요.
 em.datach(entity)	: 특정 엔티티만 준영속 상태로 전환
 em.clear()		: 영속성 컨텍스트를 완전히 초기화
 em.close()		: 영속성 컨텍스트를 종료

📌 엔티티 매핑 소개

  • 객체와 테이블 매핑 : @Entity, @Table
  • 필드와 컬럼 매핑 : @Column
  • 기본 키 매핑 : @Id
  • 연관 관계 매핑 : @ManyToOne, @JoinColumn

📌 객체와 테이블 매핑 : @Entity

  • @Entity가 붙은 클래스는 JPA가 관리, 엔티티라 g해요.
  • JPA를 사용하여 테이블과 매핑할 클래스는 @Entity 선언과 기본 생성자가 필수에요.
  • enum, interface 등과 같은 클래스는 @Entity 사용이 불가하며 저장할 필드(전역변수)에 final 사용 또한 불가능해요.

⚫ 속성 : name

  • JPA에서 사용할 엔티티 이름을 지정할 수 있는 속성이지만 기본값을 쓸 것을 권장해요.

📌 @Table

  • 엔티티와 매핑할 테이블을 지정하는 어노테이션이에요.

⚫ 속성

  • name : 매핑할 테이블 이름
  • catalog : 데이터베이스 catalog 매핑
  • schema : 데이터베이스 schema 매핑
  • DDL(uniqueConstraints) : DDL 생성 시에 유니크 제약 조건 생성

📌 데이터베이스 자동 생성

  • DDL을 애플리케이션 실행 시점에 테이블 자동 생성
  • 테이블 중심 개발 -> 객체 중심 개발로 이동
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성

📌 hibernate.hbm2ddl.auto 옵션

  • 데이터베이스 스키마 자동생성 옵션
  • create : 기존 테이블 삭제 후 다시 생성(drop+create)
  • create-drop : create와 같으나 종료 시점에 테이블 drop
  • update : 변경분만 반영
  • validate : 엔티티와 테이블이 정상 매핑되었는지
  • none : 사용하지 않음.

📌 제약 조건 추가

제약조건 : 회원 이름 필수, 길이는 10자

  • @Column(nullable = false, length = 10)
  • @Temporal : 날짜 타입 매핑
  • @Enumerated : enum 타입 매핑
  • @Lob : BLOB, CLOB (대용량을 지원해주는 컬럼) 매핑
  • @Trasient : 특정 필드를 컬럼에 매핑하지 않음

⚫ @Column

  • name : 필드와 매핑할 테이블의 컬럼 이름
  • nullable : null값의 허용 여부 설정. fasle로 설정하면 not null 제약 조건이 붙어요.
  • unique : 한 컬럼에 대해 unique하게 제약조건을 걸 때 사용
  • length : 문자 길이 제약 조건, String 타입에만 사용

📌 기본 키 매핑

  • @Id
  • @GeneratedValue

⚫ @GeneratedValue

  • 자동생성을 한다는 의미로 전략이라고 표현해요.
  • identity : 데이터베이스에 위임
  • sequence : 데이터베이스 시퀀스 오브젝트 사용 사용시엔 @SequenceGenerator가 필요해요.
  • table : 키 생성용 테이블 사용, 모든 DB에서 사용. @TableGenerator가 필요해요.
  • auto : 방언에 따라 자동 지정, 기본값

⚫ @SequenceGenerator

  • name : 식별자 이름
  • sequenceName : 데이터베이스 등록되어 있는 시퀀스 이름. 기본적으로 (hibernate_sequence) 라고 자동으로 만들어져요.
  • initialValue : 시퀀스 DDL을 생성할 때 처음 시작하는 수 지정
  • allocationSize : 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정. 기본적으로 이 값을 1로 설정
  • catalog, schema : 데이터베이스 catalog, schema 이름 설정



무사히 적응할 그 날을 기대 ✔️




출처
https://media.giphy.com/media/kyUIknbbDNvID5XzU4/giphy.gif
https://media.giphy.com/media/A6aHBCFqlE0Rq/giphy.gif

0개의 댓글