Hibernate, @SequenceGenerator 및 assignmentSize


117

우리는 모두 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>

2
"locationSize = 1을 설정하지 않고 따라서 성능이 저하됨"성능이 저하되는 이유가 1로 설정됩니까?
sheidaei

3
@sheidaei see는 아래에 주석을 달 수 있습니다. :-) 이것은 모든 save사람들이 시퀀스의 다음 값에 대해 데이터베이스를 쿼리해야하기 때문 입니다.
G. Demecki

같은 문제에 직면 해 주셔서 감사합니다. 처음에는 모든 @SequenceGenerator에 assignmentSize = 1을 추가했습니다. hibernate.id.new_generator_mappings = true를 사용하면이를 방지 할 수 있습니다. JPA는 여전히 데이터베이스를 쿼리하지만 ... 각 삽입에 대한 ID를 얻을 수
TheBakker

1
SequenceGeneratorHibernate를 사용하면 지정된 양의 ID가 부족할 때만 데이터베이스를 쿼리합니다 allocationsize. 설정하면 allocationSize = 1Hibernate가 각 삽입에 대해 DB를 쿼리하는 이유입니다. 이 값을 변경하면 완료됩니다.
G. Demecki

1
감사! hibernate.id.new_generator_mappings설정은 정말 중요합니다. ID 번호가 왜 야생인지 조사하는 데 많은 시간을 할애하지 않아도되는 기본 설정이 되었으면합니다.
LeOn-Han Li

답변:


43

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

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


감사합니다 스티브! 최고의 답변입니다. 또한 다른 게시물 이 도움이되었습니다.
G. Demecki

4
또한 귀하가의 공동 저자임을 확인했습니다 org.hibernate.id.enhanced.SequenceStyleGenerator. 당신은 나를 놀라게했습니다.
G. Demecki

22
어떻게 놀랐나요? 저는 Hibernate의 수석 개발자입니다. 나는 많은 Hibernate 클래스를 작성 / 공동 작성했습니다;)
Steve Ebersole

기록만을 위해서. 큰 간격을 방지하기 위해 DB 시퀀스 증가는 피해야합니다. ID 캐시 실행 세부 사항 out.More 때 DB 시퀀스는 allocationSize에 곱하는 stackoverflow.com/questions/5346147/...
Olcay Tarazan

1
전역 적으로 사용되는 "optimizer"를 변경하는 한 가지 방법은 hibernate 옵션에 다음과 같은 것을 추가하는 것입니다. serviceBuilder.applySetting ( "hibernate.id.optimizer.pooled.preferred", LegacyHiLoAlgorithmOptimizer.class.getName ()); LegacyHiLoAlgorithOptimizer 대신 옵티 마이저 클래스를 선택할 수 있으며 기본값이됩니다. 이렇게하면 모든 주석을 변경하지 않고도 원하는 동작을 기본값으로 더 쉽게 유지할 수 있습니다. 또한 "pooled"및 "hilo"옵티 마이저를 사용하여주의하십시오. 시퀀스 값이 0에서 시작하여 음의 ID를 유발할 때 이상한 결과를 제공합니다.
fjalvingh

17

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

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

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

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


12
성능과 관련이 없습니까? 당신은 정말 있는지? 나는 allocationSize=1모든 save작업 에서 Hibernate 를 사용하여 새로운 ID 값을 얻기 위해 데이터베이스로 이동해야 한다고 배웠다 .
G. Demecki

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

그리고 예, 할당 크기 1이 실제 성능에 영향을 미치는지 여부는 완전히 애플리케이션에 따라 다릅니다. 물론 마이크로 벤치 마크에서는 항상 큰 영향을 미칠 것입니다. 대부분의 벤치 마크 (마이크로 또는 기타)의 문제는 현실적이지 않습니다. 그리고 그것들이 다소 현실적이 될만큼 충분히 복잡하더라도, 벤치 마크 결과가 앱에서 볼 수있는 결과에 얼마나 적용 가능한지 이해하기 위해 벤치 마크가 실제 애플리케이션에 얼마나 가까운 지 살펴 봐야합니다. 긴 이야기 짧은 ... 자신을위한 테스트를
스티브 Ebersole

2
확인. 모든 것이 응용 프로그램에 따라 다릅니다. 응용 프로그램이 읽기 전용 응용 프로그램 인 경우 할당 크기 1000 또는 1을 사용하는 경우의 영향은 절대적으로 0입니다. 반면 이와 같은 것은 모범 사례입니다. 모범 사례를 존중하지 않으면 그들은 모이고 결합 된 영향은 응용 프로그램이 느려질 것입니다. 또 다른 예는 트랜잭션이 절대적으로 필요하지 않을 때 트랜잭션을 시작하는 것입니다.
Hasan Ceylan 2012 년

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 번호와 ​​일치하지 않습니다.


1

최대 절전 모드 소스 코드를 파헤 치고 아래 구성은 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;

3
죄송합니다. 이것은 매우 장황한 설정 방법입니다. 전체 Hibernate에 대해 두 개의 매개 변수로 쉽게 표현할 수 있으므로 모든 엔티티에 대해 쉽게 표현할 수 있습니다.
G. Demecki

진정한하지만 난 당신이 당신이 어떻게 구성했는지 나에게 보낼 수있는 일이 있다면 그들 중 누구도 일하지 다른 방법으로 시도 할 때
파티 흐 Tekin입니다

내 대답을 업데이트했습니다. 이제 작업 예제도 포함됩니다. 위의 의견은 부분적으로 잘못되었지만 불행히도 모든 엔티티에 대해 둘 다 allocationSize또는 initialValue전역으로 설정할 수는 없습니다 (하나의 생성기 만 사용하지 않는 한 IMHO는 읽기가 어렵습니다).
G. Demecki

1
설명을 해주셔서 감사하지만 위에서 작성한 내용을 시도했지만 최대 절전 모드 5.0.7에서 작동하지 않았습니다. 최종 버전에서이 목표를 달성 할 수 있도록 소스 코드를 파헤 쳤습니다. 최대 절전 모드 소스 코드에서. 나쁜 보일 수 있습니다 구성하지만 불행하게도 API를 최대 절전 모드 내가 최대 절전 모드의 표준 EntityManager의 구현을 사용하고 있습니다
파티 흐 Tekin입니다

1

저도 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는 오라클 시퀀스에 따라 생성됩니다.

0

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

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


당신은 내 요점을 오해하고 있습니다. ALTER SEQUENCE ... INCREMENTY BY 50;문제는 여전히 동일하기 때문에 아무것도 해결하지 못합니다. 시퀀스 값은 여전히 ​​실제 엔티티 ID를 반영하지 않습니다.
G. Demecki

여기서 문제를 더 잘 이해할 수 있도록 테스트 케이스를 공유해주세요.
Hasan Ceylan

1
테스트 케이스? 왜? 제가 올린 질문은 그다지 복잡하지 않고 이미 답변을 받았습니다. HiLo 생성기가 어떻게 작동하는지 모르는 것 같습니다. 어쨌든 : 시간과 노력을 희생 해주셔서 감사합니다.
G. Demecki

1
그레고리, 사실 제가 무슨 말을하는지 알고 있습니다. 현재 잠복중인 % 100 JPA 구현 인 Batoo JPA를 작성했으며 속도면에서 Hibernate보다 15 배 더 빠릅니다. 다른 한편으로 나는 당신의 질문을 오해했을 수도 있고 시퀀스와 함께 Hibernate를 사용하면 2003 년부터 많은 데이터베이스의 많은 프로젝트에서 Hibernate를 사용했기 때문에 전혀 문제가 발생하지 않을 것이라고 생각하지 않았습니다. 중요한 것은 당신이 질문에 대한 해결책을 가지고 있습니다, 죄송합니다 나는 올바른로 표시 답 ... 놓친
하산 세일란

죄송합니다. 기분을 상하게 할 생각은 없었습니다. 도와 주셔서 다시 한 번 감사드립니다. 질문에 대한 답변을드립니다.
G. Demecki
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.