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

궁금이님의 프로필 이미지

작성한 질문수

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

기본 키 매핑

h2 버그인가요?

해결된 질문

작성

·

785

1

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)

[질문 내용]
저는 ddl auto를 create로 하고

시퀀스 전략 했을 때,

persist 안하고 봐도

 

시퀀스가 그냥 1,

증가가 50입니다..

그 다음 persist를 한번 해 봤더니,

next value for member_seq를 한번만 호출했습니다.

 

근데 persist 2번 이상하면,

next value for member_seq를 2번 호출합니다.

시퀀스의 현재값도 101번이 됩니다.

뭔가 JPA쪽에서 놓친건가요..?

아니면 제가 뭔가 강의에서 놓친건가요?

그렇게 현재값 101번 만든 후,

이번엔 dll.auto를 none으로 해서

다시 돌려봤더니 다서 persist 해서 테이블에 저장해서 나온 건 52부터 찍힙니다.

 

 

persist 안한 것

 

 

 

 

 

persist 1번

next value for member_seq 한번 호출

 

 

 

persist 2번 호출

next value for member_seq가 두번 호출 됍니다.

 

그런데.. 이 상태에서 ddl.auto를 none으로 하고 다시 한번 로직을 실행해 봤더니..

 

어.. 제 생각이 맞다면 101부터 id가 매겨져야 할 것 같은데.. 어..

 

     public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try{
            Member member1 = new Member();
            member1.setUsername("A");
            Member member2 = new Member();
            member2.setUsername("B");
            Member member3 = new Member();
            member3.setUsername("C");

            em.persist(member1);
            em.persist(member2);
//            em.persist(member3);

            tx.commit();

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

        }

        emf.close();
    }

 

사용 버전

<?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>ex-hello-jpa</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.2.9.Final</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.214</version>
        </dependency>

    </dependencies>

</project>


답변 3

7

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

안녕하세요. 궁금이님

이것은 정상적인 상황입니다.

우선 시퀀스가 초기에 1부터 시작하는 것은 H2에서 패치가 되어서 그렇습니다. 하지만 이것은 핵심이 아니니 참고만 해주세요.

main() 메서드를 실행할 때 마다 persist를 호출하면 시퀀스가 50씩 계속 증가해서 이상하게 생각될 수 있는데요. 사실 이것은 정상적인 상황입니다.

최초에 persist를 하면 1 -> 50으로 시퀀스 값이 증가합니다. 대신에 하이버네이트가 메모리에 이 값을 기억하게 됩니다. 데이터베이스 호출 없이 메모리에서 50개의 시퀀스를 사용할 수 있는 것이지요. 따라서 성능 최적화가 됩니다. 이렇게 해서 persist를 51번 정도 하게 되면 시퀀스를 호출해서 시퀀스 값을 100으로 증가합니다. 그러면 하이버네이트는 이후 51~100까지 메모리에서 시퀀스를 할당합니다.

그러면 여기서는 왜 시퀀스가 계속 증가할까요? 그것은 main() 메서드를 계속 호출하기 때문입니다. 일반적으로는 웹 애플리케이션에서 하이버네이트를 사용합니다. 따라서 서버가 계속 떠있게 됩니다. 그런데 지금은 main() 메서드를 사용해서 자바를 실행하고 이후에 바로 자바가 종료되어 버립니다. 따라서 하이버네이트가 기억하고 있던 메모리 값도 사라지게 됩니다.

이후에 자바를 다시 실행하게 되면 하이버네이트는 메모리값이 없으므로 시퀀스를 호출해서 메모리 값을 다시 확보하게 됩니다.

결과적으로 서버를 다시 시작할 때 마다 시퀀스 값 중간에 구멍이 생기게 되는데요. 이것이 부담스러운 경우 성능 최적화를 포기하고 대신에 allocationSize를 1로 설정하시면 됩니다.

추가로 이번 강의 뒷부분을 다시 들어보시면 이해가 되실거에요^^

감사합니다.

0

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

안녕하세요. 궁금이님

좀 이상하네요. 정확한 확인을 위해서 코드를 봐야할 것 같아요.

다음 내용과 함께 실제 로컬에 다운로드 받아서 설치한 H2의 버전도 말씀해주세요.

실제 동작하는 전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 문제 영역을 실행할 수 있는 방법

2. 문제가 어떻게 나타나는지에 대한 상세한 설명

감사합니다.

궁금이님의 프로필 이미지
궁금이
질문자

답변 감사합니다.

https://drive.google.com/file/d/1apqJra6vjBZ_NEAfadh5w_YSVFMiF4ob/view?usp=sharing

insert 하지 않은 처음 상태부터 -49가 아닙니다.

근데 또 저 워크벤치? 에서 보여지는 시퀀스만 저러고 DB에는 제대로 반영이 되는 듯한 느낌 이기도 합니다.

그래서 뭔가 잘 모르겠지만 최적화를 위해 실제 시퀀스를 참조하는게 아니라 따로 계산을 하는건가? 그렇게 생각되기도 했습니다.

 

실제 깔려진 h2 버전은

image2.1.214 버전입니다.

 

재현 동영상도 일단 첨부합니다.

https://drive.google.com/file/d/1JI2vwgAs9b9gPjJKahkvqxhUAlrxqDp5/view?usp=sharing

 

재현 방법은 소스코드 중 JpaMain에 있는 main코드를 실행시키면 됩니다.

우선

<property name="hibernate.hbm2ddl.auto" value="create"/>

인 상황에서는

 

persist 없이 실행하면 시퀀스가 -49가 아닌 1 부터 시작합니다(워크벤치에서 그렇게 보여질 뿐이고 실제 시퀀스는 다를지도 모른다고 생각했습니다.)

 

그 다음, persist 1회를 해보면 제대로 DB에 id가 1로 들어갑니다.

시퀀스 호출하는 쿼리는 1번 호출됩니다.

시퀀스는 현재 값 51로 나옵니다.

 

persist 2회를 했습니다.

시퀀스 호출하는 쿼리가 2번 호출되었다고 로그에 나옵니다.

시퀀스의 현재 값은 101로 나옵니다.

 

이 상태(시퀀스 현재값이 101인 상태)에서, 이제 ddl.auto를 none으로 바꾸고 다시 persist를 2회 호출합니다.

시퀀스를 호출하는 next value for 쿼리를 1회 호출합니다.

DB에는 101번 부터가 아니라,

50번대 부터 값이 들어갔습니다.

 

DB에는 제대로 들어간 것 같은데..

워크벤치에서 보여주는 시퀀스 값이 다른 느낌입니다..

 

0

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

질문 내용을 보니 JPA와 관련된 시퀀스 생성 전략에 대한 문제로 보입니다. 하지만 저는 코드만 보고는 정확한 원인을 파악하기 어렵습니다. 해당 코드의 상황을 좀 더 자세히 파악하고 싶으시다면, 아래와 같이 해결 방법을 안내해 드릴 수 있습니다.

  1. 질문 내용에 명시하신 것과 같이 JPA의 시퀀스 생성 전략과 관련된 문제인 경우, 해당 코드가 포함된 클래스와 설정들이 있는지 확인해주시기 바랍니다.

  2. 현재 사용 중인 Hibernate의 버전과 의존성 설정 정보를 확인해주시면 도움이 됩니다.

  3. 질문 내용의 코드가 정확하게 구현되어 있는지 확인해주시기 바랍니다.

더 자세한 도움을 드리기 위해서는 질문 내용을 좀 더 구체적으로 제시해주시거나, 코드 및 설정 파일들을 공유해주시면 더욱 정확한 답변을 드릴 수 있을 것 같습니다. 감사합니다!