[java] Hibernate, @SequenceGenerator 및 assignmentSize

우리는 모두 Hibernate를 사용할 때의 기본 동작을 알고 있습니다. @SequenceGenerator실제 데이터베이스 시퀀스를 1 씩 증가시키고이 값을 50 (기본값 allocationSize) 으로 곱한 다음이 값을 엔티티 ID로 사용합니다.

이것은 잘못된 동작이며 다음과 같은 사양 과 충돌합니다 .

assignmentSize-(선택 사항) 시퀀스에서 시퀀스 번호를 할당 할 때 증가 할 양입니다.

명확하게 말하면 생성 된 ID 간의 간격에 대해서는 신경 쓰지 않습니다.

기본 데이터베이스 시퀀스와 일치하지 않는 ID에 관심이 있습니다 . 예를 들어 : 다른 애플리케이션 (예 : 일반 JDBC 사용)은 시퀀스에서 얻은 ID 아래에 새 행을 삽입하려고 할 수 있습니다. 그러나 모든 값은 이미 Hibernate에서 사용하고있을 수 있습니다! 광기.

누군가이 문제에 대한 해결책을 알고 allocationSize=1있습니까 (설정하지 않고 성능을 저하 시키지 않음 )?

편집 :
일을 명확하게하기 위해. 마지막으로 삽입 된 레코드의 ID = 1이면 HB 51, 52, 53...는 새 엔티티에 대한 값 을 사용 하지만 동시에 데이터베이스의 시퀀스 값은로 설정됩니다 2. 다른 응용 프로그램에서 해당 시퀀스를 사용할 때 쉽게 오류가 발생할 수 있습니다.

반면에 : 사양은 (내 이해에서) 데이터베이스 시퀀스가 ​​설정 51되어야하며 그 동안 HB는 범위의 값을 사용해야 한다고 말합니다.2, 3 ... 50

업데이트 :
Steve Ebersole이 아래에 언급했듯이 : 나에 의해 설명 된 동작 (그리고 많은 사람들에게 가장 직관적 인 동작)은를 설정하여 활성화 할 수 있습니다 hibernate.id.new_generator_mappings=true.

감사합니다.

업데이트 2 :
미래의 독자를 위해 아래에서 작동하는 예를 찾을 수 있습니다.

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ")
    @SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS")
    private Long id;
}

persistence.xml

<persistence-unit name="testPU">
  <properties>
    <property name="hibernate.id.new_generator_mappings" value="true" />
  </properties>
</persistence-unit>



답변

명확하게 말하면 … 설명하는 내용이 어떤 식 으로든 사양과 충돌 하지 않습니다 . 스펙은 데이터베이스 시퀀스에 실제로 저장된 값이 아니라 Hibernate가 엔티티에 할당하는 값에 대해 이야기합니다.

그러나 원하는 동작을 얻을 수있는 옵션이 있습니다. 먼저 JPA 주석과 Hibernate를 사용하여 @GeneratedValue 전략을 동적으로 선택하는 방법이 있습니까? 그것은 당신에게 기본을 줄 것입니다. 해당 SequenceStyleGenerator를 사용하도록 설정되어있는 한 Hibernate는 SequenceStyleGenerator allocationSize의 “풀링 된 최적화 프로그램”을 사용하여 해석 합니다. “풀링 된 옵티 마이저”는 시퀀스 생성시 “증가”옵션을 허용하는 데이터베이스와 함께 사용하기위한 것입니다 (시퀀스를 지원하는 모든 데이터베이스가 증분을 지원하는 것은 아닙니다). 어쨌든, 거기에서 다양한 최적화 전략에 대해 읽어보십시오.


답변

allocationSize=1Hibernate는 할당 크기 범위의 값을 할당하려고 시도하기 때문에 쿼리를 얻기 전에 마이크로 최적화이므로 시퀀스에 대한 데이터베이스 쿼리를 피하십시오. 그러나이 쿼리는 1로 설정하면 매번 실행됩니다. 다른 응용 프로그램에서 데이터베이스에 액세스하는 경우 다른 응용 프로그램에서 동일한 ID를 사용하면 문제가 발생하기 때문에 거의 차이가 없습니다.

차세대 시퀀스 ID는 assignmentSize를 기반으로합니다.

기본적으로 그것은 50너무 많은 것으로 유지됩니다 . 또한 50한 세션에서 거의 유지되지 않고이 특정 세션 및 트랜잭션을 사용하여 유지 될 레코드에 대해 거의 도움 이 될 것입니다.

따라서을 사용 allocationSize=1하는 동안 항상 사용해야 SequenceGenerator합니다. 대부분의 기본 데이터베이스 시퀀스는 항상 1.


답변

스티브 에버 솔과 다른 멤버들,
갭이 큰 (기본값은 50) 아이디에 대한 이유를 친절하게 설명해 주시겠습니까? Hibernate 4.2.15를 사용하고 있으며 org.hibernate.id.enhanced.OptimizerFactory cass에서 다음 코드를 발견했습니다.

if ( lo > maxLo ) {
   lastSourceValue = callback.getNextValue();
   lo = lastSourceValue.eq( 0 ) ? 1 : 0;
   hi = lastSourceValue.copy().multiplyBy( maxLo+1 );
}
value = hi.copy().add( lo++ );

if 문 내부에 도달 할 때마다 hi 값이 훨씬 커집니다. 따라서 빈번한 서버 재시작으로 테스트하는 동안 내 ID는
1, 2, 3, 4, 19, 250, 251, 252, 400, 550, 750, 751, 752, 850, 1100, 1150 과 같은 시퀀스 ID를 생성합니다 .

이미 사양과 충돌하지 않는다고 말씀 하셨지만 대부분의 개발자에게는 예상치 못한 상황이 될 것이라고 생각합니다.

모든 사람의 의견이 많은 도움이 될 것입니다.

지환

업데이트 : ne1410s : 편집 해 주셔서 감사합니다.
cfrick : 좋습니다. 나는 그렇게 할 것이다. 여기에 첫 번째 게시물이었고 사용 방법을 잘 모르겠습니다.

이제 maxLo가 두 가지 목적으로 사용되는 이유를 더 잘 이해했습니다. hibernate는 DB 시퀀스를 한 번 호출하고 Java 수준에서 ID를 계속 늘린 다음 DB에 저장하므로 Java 수준 ID 값은 호출하지 않고 얼마나 변경되었는지 고려해야합니다. 다음에 시퀀스를 호출 할 때 DB 시퀀스.

예를 들어, 시퀀스 ID는 한 지점에서 1이고 최대 절전 모드는 5, 6, 7, 8, 9 (locationSize = 5)로 입력되었습니다. 다음 번에 다음 시퀀스 번호를 받으면 DB는 2를 반환하지만 최대 절전 모드에서는 10, 11, 12를 사용해야합니다 … 그래서 “hi = lastSourceValue.copy (). multiplyBy (maxLo + 1)”가 DB 시퀀스에서 반환 된 2에서 다음 ID 10을 가져 오는 데 사용됩니다. 잦은 서버 재시작 동안에 만 귀찮은 일이었고 이것이 더 큰 격차에 대한 내 문제였습니다.

따라서 SEQUENCE ID를 사용하면 테이블에 삽입 된 ID가 DB의 SEQUENCE 번호와 ​​일치하지 않습니다.


답변

최대 절전 모드 소스 코드를 파헤 치고 아래 구성은 50 개 삽입 후 다음 값을 위해 Oracle db로 이동합니다. 따라서 INST_PK_SEQ가 호출 될 때마다 50 씩 증가하도록하십시오.

Hibernate 5는 아래 전략에 사용됩니다.

http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence 아래에서도 확인
하십시오.

@Id
@Column(name = "ID")
@GenericGenerator(name = "INST_PK_SEQ",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
        @org.hibernate.annotations.Parameter(
                name = "optimizer", value = "pooled-lo"),
        @org.hibernate.annotations.Parameter(
                name = "initial_value", value = "1"),
        @org.hibernate.annotations.Parameter(
                name = "increment_size", value = "50"),
        @org.hibernate.annotations.Parameter(
                name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "INST_PK_SEQ"),
    }
)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INST_PK_SEQ")
private Long id;


답변

저도 Hibernate 5에서이 문제에 직면했습니다.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
@SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE)
private Long titId;

아래와 같은 경고가 표시됩니다.

더 이상 사용되지 않는 [org.hibernate.id.SequenceHiLoGenerator] 시퀀스 기반 ID 생성기 사용이 발견되었습니다. 대신 org.hibernate.id.enhanced.SequenceStyleGenerator를 사용하십시오. 자세한 내용은 Hibernate Domain Model Mapping Guide를 참조하십시오.

그런 다음 내 코드를 SequenceStyleGenerator로 변경했습니다.

@Id
@GenericGenerator(name="cmrSeq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name = "sequence_name", value = "SEQUENCE")}
)
@GeneratedValue(generator = "sequence_name")
private Long titId;

이것은 내 두 가지 문제를 해결했습니다.

  1. 더 이상 사용되지 않는 경고가 수정되었습니다.
  2. 이제 ID는 오라클 시퀀스에 따라 생성됩니다.

답변

스키마의 시퀀스에 대해 DDL을 확인합니다. JPA 구현은 올바른 할당 크기를 가진 시퀀스 생성 만 담당합니다. 따라서 할당 크기가 50이면 시퀀스는 DDL에서 50 씩 증가해야합니다.

이 경우는 일반적으로 할당 크기가 1 인 시퀀스를 생성 한 다음 나중에 할당 크기 50 (또는 기본값)으로 구성 할 때 발생할 수 있지만 시퀀스 DDL은 업데이트되지 않습니다.


답변