// JpaTest.java
@Configuration
public class JpaTest {
private EntityManager em;
private EntityTransaction tx;
@Bean
public CommandLineRunner testJpaBasicRunner(EntityManagerFactory emFactory) {
this.em = emFactory.createEntityManager();
this.tx = em.getTransaction();
return args -> {
ex1();
ex2_1stcache();
ex3_select();
ex4_equals();
ex5_delaycommit();
ex6_dirtychecking();
emFactory.close();
};
}
}
// MyMember.java
@Entity
@NoArgsConstructor
@Getter
@Setter
public class MyMember {
@Id
private Long id;
private String name;
}
EntityManagerFactory
을 주입 받아 EntityManager
와 EntityTransaction
을 사용하기 위해 em,tx에 할당하였다. private void ex1() {
tx.begin();
MyMember myMember = new MyMember();
myMember.setId(1L);
myMember.setName("HelloA");
em.persist(myMember);
tx.commit();
em.close();
}
em.persist(myMember);
가 호출되면 엔티티 메니저가 , 엔티티 객체는 영속성 컨텍스트의 1차 캐시에 영속화 되며 JPA의 관리하에 들어오게 된다.myMember
엔티티 데이터를 저장하기 위한 쿼리문이 저장되게 된다.tx.commit();
동시에 내부적으로는 em.flush()
가 실행되며, DB로 쿼리문이 날아가 엔티티는 DB에 저장되고 트랜젝션은 끝나게 된다.em.close();
를 통해 엔티티 매니저를 종료된다.ex2_1stcache()
,ex3_select()
private void ex2_1stcache() {
tx.begin();
/* 비영속 상태 */
MyMember myMember = new MyMember();
myMember.setId(1L);
myMember.setName("helloJPA");
/* 영속 1차 캐시*/
System.out.println("Berore==============");
em.persist(myMember);
System.out.println("After===============");
/* 쿼리문이 날아가지 않음 - 영속성 컨텍스트의 1차캐시에서 데이터를 가져오기 때문 */
MyMember findMyMember = em.find(MyMember.class, 1L);
System.out.println("findMember.getId() = " + findMyMember.getId());
System.out.println("findMember.getName() = " + findMyMember.getName());
tx.commit();
/* 영속 상태로 만들고 컨텍스트를 비운다 */
em.clear();
}
private void ex3_select() {
tx.begin();
/* 영속성 컨텍스트에는 현재 존재하고 있는 1차 캐시 데이터가 없기때문에 셀렉 쿼리를 날려서 데이터를 가져오게된다*/
MyMember reFindMyMember = em.find(MyMember.class, 1L);
System.out.println("reFindMember.getId() = " + reFindMyMember.getId());
System.out.println("reFindMember.getName() = " + reFindMyMember.getName());
em.close();
}
ex2_1stcache()
에서 새로운 엔티티 객체를 생성하여 em.persist(myMember);
로 영속화 하게 되면, 1차 캐시에 데이터가 저장되게 되며, MyMember findMyMember = em.find(MyMember.class, 1L);
em.find()
를 호출한 시점에 쿼리문이 날아가지 않은 것을 확인 할수 있다.persist()
후 엔티티 메니저가 종료되거나 비워지지 않았다면 해당 데이터를 DB에 거치지 않고 조회 할수 있게 된다.em.clear();
를 호출하여 엔티티 메니저를 비운 후 ex3_select()
의 새로운 트랜잭션에서 em.find(MyMember.class, 1L);
를 하게되면ex4_equals()
private void ex4_equals() {
tx.begin();
/* 비영속 상태 */
MyMember myMember = new MyMember();
myMember.setId(1L);
myMember.setName("helloJPA");
em.persist(myMember);
tx.commit();
em.clear();
tx.begin();
MyMember findMyMember1 = em.find(MyMember.class, 1L);
MyMember findMyMember2 = em.find(MyMember.class, 1L);
System.out.println("findMember1 equals findMember2 = "+ findMyMember1.equals(findMyMember2));
em.close();
}
em.persist(myMember);
, tx.commit();
, em.clear();
차례로 호출하여 DB에 데이터를 저장하고 엔티티 매니저를 비웠다.em.find(MyMember.class, 1L);
로 같은 영속 엔티티를 두번 호출하여 두개의 변수에 할당해준다.equals()
로 두개의 객체가 같은지 확인 해보면, true를 반환한다.ex5_delaycommit()
private void ex5_delaycommit() {
tx.begin();
MyMember myMember1 = new MyMember();
myMember1.setId(1L);
myMember1.setName("helloJPA");
MyMember myMember2 = new MyMember();
myMember2.setId(2L);
myMember2.setName("helloSpring");
System.out.println("Persist Berore==============");
em.persist(myMember1);
em.persist(myMember2);
System.out.println("Persist After===============");
System.out.println("Commit==============");
tx.commit();
em.close();
}
System.out.println("Commit==============");
이 실행 된 이후에 쿼리문이 날아가는 것을 확인 할 수 있다.commit()
이 호출되는 시점에 쿼리문이 날아가도록 쓰기지연 기능을 지원하는 것을 확인 할 수 있다.ex6_dirtychecking()
private void ex6_dirtychecking() {
tx.begin();
MyMember myMember1 = new MyMember();
myMember1.setId(1L);
myMember1.setName("helloJPA");
em.persist(myMember1);
tx.commit();
em.clear();
tx.begin();
MyMember findMyMember1 = em.find(MyMember.class, 1L);
System.out.println("findMember1.getName() = " + findMyMember1.getName());
findMyMember1.setName("helloSpring");
tx.commit();
em.clear();
tx.begin();
MyMember findMyMember2 = em.find(MyMember.class, 1L);
System.out.println("findMember2.getName() = " + findMyMember2.getName());
em.close();
}
persist()
를 호출하여 영속성 컨텍스트에 등록 후 commit()
으로 DB에 저장하고 엔티티 매니저를 초기화 했다.persist()
를 호출 하지 않고 commit()
만 호출한 다음, 엔티티 매니저를 초기화 했다."helloSpring"
인 것을 확인 할수 있다.persist()
를 호출하지 않더라도 commit()
이 호출되는 시점에 엔티티의 변경된 데이터를 감지하여 업데이트 쿼리문을 자동을 날려 주는 것을 확인할 수 있다.clear()
: 영속성 컨텍스트 초기화.close()
: 영속성 컨텍스트 종료.merge()
: 준영속(영속 상태였다가 영속성 컨텍스트에서 제거된 엔티티) 상태의 엔티티를 영속상태로 만들어 준다.detach(entity)
: 해당 엔티티를 준영속 상태로 만든다.flush()
: 영속상태의 데이터를 DB에 저장한다.Reference
https://www.baeldung.com/jpa-hibernate-persistence-context
https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html