JPA CRUD(+ 영속 컨텍스트, Dirty Checking)

KMS·2022년 4월 1일
0

JPA Basics

목록 보기
3/20
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); // /persistence.xml => <persistence-unit name="hello">
        EntityManager em = emf.createEntityManager(); //테이블 접근 시, 무조건 EntityManager 을 통해서 해야됨

        EntityTransaction transaction = em.getTransaction(); //JPA 에서의 모든 데이터 변경을 EntityTransaction 으로 이루어짐

        transaction.begin(); // 데이터베이스 transaction 을 시작
        em.createQuery("delete from Member").executeUpdate(); //실행 할때마다 테이블의 모든 튜플들 삭제
        transaction.commit();


        //Create
        Member memberA = new Member();
        memberA.setId(1L);
        memberA.setUsername("hello"); // Member 테이블에 저장할 튜플 생성

        Member memberB = new Member();
        memberB.setId(2L);
        memberB.setUsername("helloB"); // Member 테이블에 저장할 튜플 생성

        try {
            transaction.begin(); // 데이터베이스 transaction 을 시작; 이전에 transaction.commit()을 했으면 다시 begin()을 해줘야 함

            /**
             * Member 테이블에 memberA && memberB 객체들 적재
             */
            em.persist(memberA);
            em.persist(memberB);
            

            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }


        //Remove
        try {
            transaction.begin(); // 데이터베이스 transaction 을 시작

            /**
             * Column id로 원하는 튜플을 찾아서 객체로 반환 받고, 해당 객체를 제거
             */
            Member findMember = em.find(Member.class, 2L);
            em.remove(findMember);

            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }
        
        //Update
        try {
            transaction.begin(); // 데이터베이스 transaction 을 시작

            /**
             * Column id로 원하는 튜플을 찾아서 객체로 반환 받고, 해당 객체의 값을 수정
             */
            Member findMember = em.find(Member.class, 1L);
            findMember.setUsername("helloJPA"); // persist()을 하지 않아도 자동으로 테이블이 업데이트 됨

            transaction.commit(); //commit을 통해 변화 반영
        } catch (Exception e) {
            transaction.rollback();
        }


        try {
            /**
             * 쿼리문으로 원하는 값 찾기
             * select *from member
             */
            List<Member> memberList = em.createQuery("select m from Member as m", Member.class)
                    .getResultList();
            for (Member mem : memberList) {
                System.out.println("member.name = " + mem.getUsername());
            }

        } catch (Exception e) {

        }

        //항상 EntityManager랑 EntityManagerFactory를 close() 해줌
        em.close(); 
        emf.close();
  • persist(객체) 로 객체를 테이블에 저장

  • remove(객체) 로 객체를 테이블에서 제거

  • 수정할 객체를 find(객체) 로 찾고, 반환 받은 객체의 값들을 수정하면 테이블에서도 수정이 됨

  • 테이블에 튜플을 적재, 삭제, 수정 등을 하고 commit()을 해줘야 반영 됨

  • 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유

  • 엔티티 매니저는 쓰레드간에 공유X (사용하고 버려야 한다)

======= 영속 컨텍스트(EntityManager) 추가 설명 ======

EntityManager.persist(객체)

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

//1차 캐시에 저장됨
em.persist(member);

EntityTransaction.commit()이 일어나기 전에는 엔티티가 DB에 저장되어 있지 않음. 1차 캐시에 엔티티가 저장되고, Buffer SQL 저장소에 INSERT INTO SQL문이 저장되어 있는 상태로 있음

EntityManager.find(객체)

Member findMember2 = em.find(Member.class, "member2");
//'member2' 가 1차 캐시에는 없고, 이미 DB에 저장되어 있는 상태

우선, 1차 캐시에서 엔티티가 있는지 조회하고, 없을 경우 DB를 조회함
DB에 엔티티가 있을 경우 1차 캐시에 반환해서 저장해줌

영속 엔티티의 동일성 보장

1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭
션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공.

EntityManager.persist(객체) -> EntityTransaction.commit()

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

//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); 

memberA 엔티티랑 memberB 엔티티가 1차 캐시에 저장되고, EntityTransaction.commit()이 일어나기 전까지는 DB에 저장되지 않음. 1차 캐시에 우선 저장되고, 각 엔티티에 대한 INSERT INTO SQL문이 Buffer SQL 저장소에 저장되어 있음.
commit()이 발생하면 Buffer SQL 저장소에 저장되어 있는 SQL문들이 실행됨

엔티티 수정

// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);

transaction.commit();

  • setter로 엔티티의 속성 값을 수정 -> commit() 실행 하면 flush() 실행 -> 엔티티와 스냅샷을 모두 비교해서 수정된 스냅샷 찾음 -> UPDATE SQL문을 작성해서 Buffer SQL 저장소에 저장 -> Buffer SQL 저장소에 저장된 SQL문들 실행 -> DB에 수정된 부분 반영
  • Dirty Checking: 엔티티의 속성 값을 수정하면, JPA에서 값이 변경됐는지 감지를 하고, 변경 됐으면 해당 값에 대한 update 쿼리문을 자동으로 실행 시켜준다.
profile
Student at Sejong University Department of Software

0개의 댓글