인프런 커뮤니티 질문&답변

ksg980105님의 프로필 이미지

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

벌크 연산

flush commit 이해가 안되는부분이있습니다.

해결된 질문

작성

·

613

·

수정됨

0

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예

[질문 내용]
여기에 질문 내용을 남겨주세요.

 

 

            Team teamA = new Team();
            teamA.setName("팀A");
            em.persist(teamA);

            Team teamB = new Team();
            teamB.setName("팀B");
            em.persist(teamB);



            Member member1 = new Member();
            member1.setUsername("회원1");
            member1.setTeam(teamA);
            em.persist(member1);

            Member member2 = new Member();
            member2.setUsername("회원2");
            member2.setTeam(teamA);
            em.persist(member2);

            Member member3 = new Member();
            member3.setUsername("회원3");
            member3.setTeam(teamB);
            em.persist(member3);
            
            int resultCount = em.createQuery("update Member m set m.age=20")
                    .executeUpdate();
            em.clear();
            Member findMember = em.find(Member.class, member1.getId());
            System.out.println("findMember = " + findMember.getAge());

            System.out.println("resultCount = " + resultCount);
            tx.commit();
            System.out.println("resultCount = " + resultCount);


        } catch (Exception e) {

 

해당 코드를 보면

  em.clear();

이걸하면 영속성 컨텍스트를 초기화해서

db 에서 값을 가져온다는데요

tx.commit(); 하기 전에는 breakpoint 를 찍어보면

db 에 반영이 안되어있는데

어디 db 에서 가져온다는 말인지 잘 이해가 안됩니다..

즉 한마디로

1.em.clear(); 을 하면 영속성컨텍스트 전체 초기화
2.findMember.getAge() 이 동작을 할때

영속성컨텍스트에 값이 없으므로 Db 에서 가져옴


3. 하지만 commit 하기전 그 시점엔 db에는 아무값이 없다
(flush 의 경우에도 마찬가지 insert 가 적혀있어도 커밋 직전엔 실제 db에는 아무 값이 없다)

도대체 어떤 db에만 반영되었고
(이건 임시 db인건가) 가져온다는 말인지..
왜냐하면 그때 실제 db에는 그 당시에 아무값도 없기때문

(commit 이 일어나지 않았기 때문에)

 

(하지만 System.out.println("findMember = " + findMember.getAge()););
이 결과로보면 findMember.getAge()의 20이란 숫자를 select 해서 가져온건 맞음
도대체 어디서 select 를 했단 말인가..)

 

-콘솔 결과값

이 순간 ! db 를 조회하면 (tx.commit 을 안했을 가정.)

 

 



ps. 제가말한 Db 는 h2 콘솔에서 조회했을때입니다.

콘솔에서 조회했을때는 안보이는데 분명 어딘가의 db 는 바뀐게 맞는거같아요


db에있는 20이라는 숫자를 어디서 가져오는지가 궁금합니다.


답변 2

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. ksg980105님

플러시가 발생해야 em.persist()한 내용들을 DB에 반영해주는데요.

플러시는 트랜잭션을 커밋하거나 또는 JPQL을 실행할 때 자동으로 발생합니다.

따라서 다음 JPQL을 실행할 때 플러시가 발생합니다.

em.createQuery("update Member m set m.age=20")

이때 이미 모든 데이터가 DB에 반영되고, update 쿼리 또한 DB에 반영됩니다.

따라서 이후에 조회하게 되면 20이라는 값이 조회됩니다.

DB에서 데이터를 확인할 수 없는 이유는 애플리케이션이 시작한 트랜잭션의 변경 데이터는 커밋하기 전까지 다른 곳에 보이지 않습니다.

이것을 트랜잭션 격리라 합니다.

애플리케이션에서 시작한 트랜잭션을 커밋하면 이후에 DB 접속 툴을 포함한 다른 트랜잭션에서도 데이터를 확인할 수 있습니다.

플러시에 대한 내용은 본 강의 앞 부분의 플러시 부분을 참고해주세요.

애플리케이션과 DB 트랜잭션에 대한 내용은 스프링 DB1편을 참고해주세요.

감사합니다.

ksg980105님의 프로필 이미지
ksg980105
질문자

아 트랜젝션 격리때문에 그런거군요!

완전히 이해했습니다! 스프링 DB1편도 수강해야겠네요 항상 너무나도 감사합니다 ㅠㅠ!

1

안녕하세요, 인프런 AI 인턴이에요.

질문하신 내용을 보니 flush와 commit에 대한 이해를 하고 싶으신 것 같아요. flush와 commit은 JPA에서 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 작업입니다.

flush는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업이에요. 하지만, 트랜잭션이 아직 커밋되지 않았다면 변경 내용은 데이터베이스에 반영되지 않고, 영속성 컨텍스트에만 적용되는 것이 특징입니다.

반면, commit은 트랜잭션의 작업을 완전히 처리하고 데이터베이스에 영구적으로 반영하는 작업이에요. commit이 호출되면 트랜잭션은 종료되고, 영속성 컨텍스트의 변경 내용이 데이터베이스에 반영됩니다.

즉, flush는 영속성 컨텍스트와 데이터베이스를 동기화하는 작업이고, commit은 트랜잭션 작업을 종료하고 데이터베이스에 변경 내용을 영구적으로 반영하는 작업이에요.

이와 관련해서 한 가지 주의할 점은 flush를 명시적으로 호출하면 성능상 문제가 발생할 수 있으니, 필요한 경우에만 사용하는 것이 좋다는 점이에요.

더 자세한 내용은 JPA 관련 문서나 강의를 참고해보시면 도움이 될 거에요. 질문이 더 있으시다면 언제든지 물어보세요!

ksg980105님의 프로필 이미지
ksg980105
질문자

그러면 commit 전에 flush 를 해서 쿼리를 실행시켜 데이터를 변경하면

변경된 데이터를 사용할수 있는데

데이터베이스 서버 임시 영역에 저장된 데이터를 사용한건가요?

 

flush 가 영속성컨텍스트랑 데이터를 동기화했다고 하는데 해당 데이터가 commit을 안해서 반영이 안된 상태인데

어떻게 동기화가 된 상태가 된거죠? (clear 을 해서 영속성 컨텍스트에는 아무 값이 없고 그렇기에 데이터에서 값을 가져오는걸로 알고있는데.. 데이터가 commit 을 안해서 반영이 안되었으니 )

실제로는 반영되어 동기화가 된거처럼 동작하긴 합니다.

김영한님의 프로필 이미지
김영한
지식공유자

이 부분을 이해하시려면 JPA와 무관하게 데이터베이스 트랜잭션을 이해하셔야 합니다.

우리가 데이터베이스에 insert, update 쿼리를 날리면 트랜잭션을 시작한 곳에서만 변경된 데이터를 확인할 수 있고, 다른 곳에서는 변경된 데이터를 확인할 수 없습니다. 이후에 트랜잭션을 커밋하면 다른 곳에서도 변경된 내역을 확인할 수 있습니다.

결과적으로 커밋하기 전에도 데이터베이스에 실제 데이터가 전달 됩니다. 다만 커밋을 해야 다른 곳에서 변경된 데이터를 확인할 수 있고, 롤백을 하게 되면 변경한 데이터가 반영되지 않습니다.

관련해서 스프링 DB 1편 - 데이터 접근 핵심 원리 강의에서 데이터베이스 트랜잭션 개념을 자세히 설명해드립니다. 참고해주세요 :)