빡코

[JPA][개념] 영속성 관리 본문

Java/JPA

[JPA][개념] 영속성 관리

chris.djang 2023. 2. 10. 23:15

[추후 정리할 내용]

Java Persitsence API 

ORM  : Object Relation Mapping 객체-관계 매핑

객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결) 해주는 것 

RDB 

ORM은 객체와 RDB 두 기둥위에 있는 기술이다.

JPA와 hibernate의 관계?

 

groupId?

- 모든 프로젝트 중에서 당신의 프로젝트를 식별하게 해주는 식별자

- groupId는 Java의 패키지 이름 규칙을 따라야 함 즉 제어하는 도메인 이름의 반대로 시작

  ex ) org.apache.maven, org.apache.commons 

- 만약에 프로젝트가 다중 모듈 프로젝트인 경우 부모의 groupId에 새 식별자를 추가해 사용

  ex ) org.apache.maven, org.apache.maven.plugins, org.apache.maven.reporting

 

artifactId?

  • artifactId는 버전 정보를 생략한 jar 파일의 이름이다.
    • 이름은 원하는 것으로 아무거나 정해도 괜찮다.
    • 단, 소문자로만 작성하도록 한다.
    • 단, 특수문자는 사용하지 않는다.
  • 만약 써드 파티 jar 파일이라면, 할당된 이름을 사용해야 한다.
    • 예: maven, commons-math

 

 

JPA 셋팅(H2 데이터베이스 +  Maven + hivernate)

Project 구조 

 

pom.xml (라이브러리 생성)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jpa-basic</groupId>
    <artifactId>ex1-hello-jpa</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


    <dependencies>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>

        <!-- JPA 하이버네이트 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.3.10.Final</version>
        </dependency>
        <!-- H2 데이터베이스 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
        </dependency>
    </dependencies>


</project>

 

JPA 설정 파일 세팅 

<?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"> //JPA 이름은 멀쓸꺼야? 
        <properties>
            <!-- 필수속성 --> //데이터베이스 접근 정보를 넣어줘야 한다. 
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value=""/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.url" value="주소"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> //데이터베이스 방언 지정
            
            <!-- 옵션 -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments" value="true"/>
            <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>
</persistence>

 

데이터베이스방언

hibernate.dialect속성에지정

H2 : org.hibernate.dialect.H2Dialect

Oracle 10g : org.hibernate.dialect.Oracle10gDialect

MySQL : org.hibernate.dialect.MySQL5InnoDBDialect

하이버네이트는 40가지이상의데이터베이스방언지원

 

 

JPA 구동방식 

주의

엔티티 매니저 팩토리하나만 생성해서 애플리케이션 전체에공유
엔티티매니저쓰레드간에 공유X (사용하고버려야한다).
JPA모든 데이터 변경은 트랜잭션 안에서 실행
 
JPQL 
•JPA를 사용하면 엔티티객체를 중심으로 개발 
•문제는 검색쿼리 
•검색을 할 때도 테이블이 아닌 엔티티객체를 대상으로 검색 
•모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능 
•애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색조건이 포함된 SQL이필요 
•JPA는 SQL을추상화한 JPQL이라는 객체지향쿼리언어제공 
•SQL과 문법유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원 
•JPQL은 엔티티객체를 대상으로 쿼리 
•SQL은 데이터베이스 테이블을 대상으로 쿼리 
•테이블이 아닌 객체를 대상으로 검색하는 객체지향쿼리 
•SQL을 추상화해서 특정데이터베이스 SQL에 의존 X 
•JPQL을 한마디로 정의하면 객체지향 SQL 
•JPQL은 뒤에서 아주 자세히 다룸
 
예제 코드 
package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaMain {
    public static void main(String[] args) {
        //데이터베이스 하나당 하나씩 묶여서 돌아감
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        //고객의 요청이 올때 EntityManager 생성해서 실행  
        EntityManager em = emf.createEntityManager();

        //Transaction 안에서 진행되어야 한다.
        EntityTransaction tx = em.getTransaction();
        tx.begin(); //Transaction 시작


        try {

            //멤버 저장
            //Member member = new Member();
            //member.setId(2L);
            //member.setName("HelloA");
            //Member findMember = em.find(Member.class, 1L); //찾기
            //findMember.setName("HelloJPA"); //수정 -> 따로 저장할 필요 없음
            //em.persist(member); //저장

            //jpql
            //멤버 객체를 다가져와(대상이 Table이 아니다)
            List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .setFirstResult(1)
                    .setMaxResults(10)
                    .getResultList();
            for( Member member : result) {
                System.out.println("member.name = " + member.getName());
            }
            
            tx.commit();

        } catch ( Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}
package hellojpa;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Member {

    @Id
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
 
영속성 컨텍스트(Entity Manager)
  • 엔티티를 영구 저장하는 환경 이라는 뜻
  • 영속성 컨텍스트는 눈에 보이지 않는 논리적인 개념이다. 
  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다. 
  • 비영속(new/transient) 영속성 컨텍스트와 전현 관계가 없는 새로운 상태
  • 영속(managed) 영속성 컨텍스트에 관리되는 상태
  • 준영속(detatched) 영속성 컨텍스트에 저장되었다가 분리가 된 상태  
  • 삭제(removed) 삭제된 상태 

 

 

 

 

영속성 컨텍스트의 이점 

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

1차 캐시

 

 

 

 

 

 

 

 

 

엔티티수정(변경감지_Dirty Checking)

 

 

 

 

 Flush

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 과정이다(싱크 맞추는 작업)

플러시가 발생되는 상황은?

  • 변경감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)
영속성 컨텍스트를플러시하는 방법
em.flush() - 직접 호출(강제 호출)
트랜잭션 커밋 - 플러시 자동 호출
JPQL 쿼리 실행 - 플러시 자동 호출
 
 
플러시 모드 옵션
em.setFlushMode(FlushModeType.COMMIT)
FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시 (기본값)
FlushModeType.COMMIT : 커밋할 때만 플러시
플러시는?
영속성 컨텍스트를 비우지 않음
영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
트랜잭션이라는 작업 단위가 중요 > 커밋 직전에만 동기화 하면 됨
 
 
준영속 상태?
영속 -> 준영속
영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
영속성 컨텍스트가 제공하는 기능을 사용 못함
 
준영속 상태로 만드는 방법
em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
em.clear() : 영속성 컨텍스트를 완전히 초기화 (1차 캐시를 통으로 다 지우는 작업)
em.close() : 영속성 컨텍스트를 종료
 
            //영속
            Member member = em.find(Member.class, 150L);//영속상태
            member.setName("AAAA");

            em.detach(member); //JPA에서 더이상 관리하지 않음
            
            tx.commit();//inset query가 나가는 시점
 
 

'Java > JPA' 카테고리의 다른 글

[JPA][개념] 프록시와 연관관계 정리  (0) 2023.03.23
[JPA][개념] 상속관계  (0) 2023.02.22
[JPA][개념]다양한 연관관계 매핑  (0) 2023.02.17
[JPA][개념] 엔티티 매핑  (0) 2023.02.14
[JPA][기본개념] 정리  (0) 2023.02.06