핵심 키워드 : 변경 감지, 커밋, 스냅샷, Transaction
효율적인 데이터 업데이트
작업을 가능하게 하는 중요한 기능입니다. 이 과정은 다음과 같이 이루어집니다.
이 기능 덕분에 개발자는 데이터를 업데이트하기 위해 별도의 update 메서드를 호출할 필요가 없습니다. Entity 객체의 값을 변경하기만 하면 JPA가 나머지를 알아서 처리합니다. 이는 애플리케이션 코드를 더 간결하고 명확하게 만들어 줍니다.
JPA
를 사용하여 DB에 데이터를 저장, 조회, 수정, 삭제도 가능합니다.# 생성한 database name : memo
<?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="memo">
<class>com.sparta.entity.Memo</class>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jakarta.persistence.jdbc.user" value="root"/>
<property name="jakarta.persistence.jdbc.password" value="{비밀번호}"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/memo"/>
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
</properties>
</persistence-unit>
</persistence>
# JPA는 **persistence.xml** 의 정보를 토대로 EntityManagerFactory를 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("memo");
# EntityManagerFactory를 사용하여 EntityManager를 생성
EntityManager em = emf.createEntityManager();
여러 개의 SQL이 하나의 트랜잭션에 포함될 수 있습니다.
모든 SQL이 성공적으로 수행이 되면 DB에 영구적으로 변경을 반영하지만, SQL 중 단 하나라도 실패한다면 모든 변경을 되돌립니다.
JPA에서도 영속성 컨텍스트로 관리하고 있는 변경이 발생한 객체들의 정보를 쓰기 지연 저장소에 전부 가지고 있다가 마지막에 SQL을 한번에 DB에 요청해 변경을 반영합니다.
EntityTransaction 성공 테스트
@Test
@DisplayName("EntityTransaction 성공 테스트")
void test1() {
EntityTransaction et = em.getTransaction(); // EntityManager 에서 EntityTransaction 을 가져옵니다.
et.begin(); // 트랜잭션을 시작합니다.
try { // DB 작업을 수행합니다.
Memo memo = new Memo(); // 저장할 Entity 객체를 생성합니다.
memo.setId(1L); // 식별자 값을 넣어줍니다.
memo.setUsername("Robbie");
memo.setContents("영속성 컨텍스트와 트랜잭션 이해하기");
em.persist(memo); // EntityManager 사용하여 memo 객체를 영속성 컨텍스트에 저장합니다.
et.commit(); // 오류가 발생하지 않고 정상적으로 수행되었다면 commit 을 호출합니다.
// commit 이 호출되면서 DB 에 수행한 DB 작업들이 반영됩니다.
} catch (Exception ex) {
ex.printStackTrace();
et.rollback(); // DB 작업 중 오류 발생 시 rollback 을 호출합니다.
} finally {
em.close(); // 사용한 EntityManager 를 종료합니다.
}
emf.close(); // 사용한 EntityManagerFactory 를 종료합니다.
}
em.persist(memo);
메서드가 호출되면 memo Entity 객체를 캐시 저장소에 저장합니다. @Test
@DisplayName("1차 캐시 : Entity 저장")
void test1() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = new Memo();
memo.setId(1L);
memo.setUsername("Robbie");
memo.setContents("1차 캐시 Entity 저장");
em.persist(memo); // 캐시 저장소에 저장
et.commit();
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
em.find(Memo.class, 1);
호출 시 캐시 저장소를 확인 한 후 해당 값이 없다면?@Test
@DisplayName("Entity 조회 : 캐시 저장소에 해당하는 Id가 존재하지 않은 경우")
void test2() {
try {
Memo memo = em.find(Memo.class, 1);
System.out.println("memo.getId() = " + memo.getId());
System.out.println("memo.getUsername() = " + memo.getUsername());
System.out.println("memo.getContents() = " + memo.getContents());
} catch (Exception ex) {
ex.printStackTrace();
} finally {
em.close();
}
emf.close();
}
Memo memo = em.find(Memo.class, 1);
호출 시 캐시 저장소에 해당 값이 존재하지 않기 때문에 DB에 SELECT 조회하여 캐시 저장소에 저장한 후 반환합니다.em.find(Memo.class, 1);
호출 시 캐시 저장소에 식별자 값이 1이면서 Memo Entity 타입인 값이 있는지 조회합니다.em.remove(entity);
em.remove(memo);
호출 시 삭제할 Entity를 DELETED 상태로 만든 후@Test
@DisplayName("Entity 삭제")
void test5() {
EntityTransaction et = em.getTransaction();
et.begin();
try {
Memo memo = em.find(Memo.class, 2);
em.remove(memo);
et.commit();
} catch (Exception ex) {
ex.printStackTrace();
et.rollback();
} finally {
em.close();
}
emf.close();
}
이번 내용은 다시 공부해보고, 영속성 컨텍스트에 대해서 더 찾아서 공부해야겠다.