2011-02-16 7 views
3

나는 진정으로 의아해합니다 ...하지만 먼저, 대략적인 개요를 드리겠습니다.데이터베이스와 JPA에서 서로 다른 PostgreSQL 시퀀스 ID

저는 4 개의 테이블을 2 개로 병합하여 데이터베이스에서 일부 구조 조정을했습니다. 모든 테이블에는 기본 숫자 키로 간단한 숫자 시퀀스가 ​​있습니다. 테이블은 실제로 쌍으로 아주 (매우) 비슷했습니다. 두 가지로 분리 된 유일한 이유는 가져와야하는 역사적인 데이터를 기반으로했습니다. 이 분할이 없었다면 많은 중복성이 있었을 것이고 개념적으로는 의미가 있습니다.

이제 데이터 정리에 많은 노력을 기울인 후에 마침내이를 병합하고 필드 중 하나를 판별 자로 사용하기 만하면됩니다. 덜 추상적 인 이야기를하기 위해 테이블에는 기업이 포함되어 있습니다. 그리고 그들은 지역 주민이거나 그렇지 않습니다 (두 클래스). 우편 번호 (판별 자 필드)로 쉽게 구별 할 수 있습니다. 이 테이블은 천천히 변화하는 차원입니다 (시퀀스가 서로 게이트입니다). 다른 두 테이블에는 이러한 SCD에 첨부 된 일반 데이터가 들어 있습니다. 따라서 4 개의 테이블. 2 개는 현지 회사, 2 개는 비 주민용입니다.

이 표는 이제 단순화되고 병합되었으므로 이제는 CompanyCompanyData 만 있습니다.

역사적인 정보가 손실되지 않도록 안전하고 새로운 시퀀스 필드가있는 두 개의 새 테이블을 만들었습니다. 10 년 후 예전의 순서가 유지됩니다. 뭔가 잘못되었다는 것을 깨닫게됩니다.)

지금까지 그렇게 좋았습니다.

구조 조정은 매우 쉽고, 올바른 항목을 다시 연결하는 것도 간단합니다. 다음으로이 DB와 ​​인터페이스하는 응용 프로그램을 업데이트해야했습니다.이 작업은 좀 더 쉽지만 여전히 쉽습니다. 이 애플리케이션은 이미 PostgreSQL 9.0 데이터베이스 위에 EclipseLink 2.0을 사용하여 JPA를 사용합니다. 나는 새로운 회사를 삽입 할 때

, 나는 주어진 ID가 이미 존재한다는, 중복 키 오류가 발생합니다 :

그리고 여기가 이상한 부분을 온다. 하지만 그것은 시퀀스 객체에 의해 처리되어야합니다 ... 그렇지 않아야합니까?

그래서 나는 주위를 파고 들었다. 연속적인 비활성으로 인해 실제로 번으로 개의 ID가 중복 된 키 오류가 반환되는지 확인할 수있었습니다. 즉, 시퀀스 논리가 OK입니다. 유일한 문제는 현재 값이 너무 낮다는 것입니다. 따라서 nextval (또는 JPA가 사용하는 것)을 호출하면 이미 존재하는 ID가 반환됩니다.

@Id 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "enterprise_id_seq") 
@Column(name = "id", nullable = false) 
private Integer id; 

그리고 내 순서는 다음과 같습니다 :

나는이 (가) JPA 엔티티에 다음이

[...] 

Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.1.v20100213- 
r6600): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "enterprise_pkey" 
    Detail: Key (id)=(19611) already exists. 
Error Code: 0 
Call: INSERT INTO en... 

[...] 

로 :

test_db=# \d enterprise_id_seq 
     Sequence "public.enterprise_id_seq" 
    Column  | Type |  Value   
---------------+---------+--------------------- 
sequence_name | name | enterprise_id_seq 
last_value | bigint | 19659 
start_value | bigint | 1 
increment_by | bigint | 1 
max_value  | bigint | 9223372036854775807 
min_value  | bigint | 1 
cache_value | bigint | 1 
log_cnt  | bigint | 32 
is_cycled  | boolean | f 
is_called  | boolean | t 

오류 나는 얻을이 있습니다 id가 19611 인 엔티티를 삽입하려하지만 시퀀스의 마지막 값은입니다.. 분명히 틀렸어.

나는 또한이 모든 것의 뒤에서 응용 프로그램 서버를 다시 시작하여 열려있는 모든 연결과 세션을 닫으려고했습니다. 행운을 빌어 요 ... 내가 알아챈 또 다른 것 :이 필드는 Integer으로 정의됩니다. 오히려 Long일까요? 이는 코드의 변경을 필요로 할 것이며 아직 수정하지는 못했습니다.단순히 삽입 50 번 실행을 시도 할 수 있습니다,하지만 난 오히려 잘못되었는지 정확히 알 것 뒤에 난 단지 50 개 항목 해요으로

...

내가 무슨 말이냐?

업데이트

: 좀 더 파고 후, 나는 흥미롭게도,이 제가 보는 ID의 차이에 상당히 가깝게 (50)의 기본을 가지고 allocationSize을 가로 질러왔다. 일부 테스트 및 조정으로 인해 100 % 동일하지 않을 수도 있습니다. 그것은 관련 될 수 있습니까? 솔직히이 설정 뒤에있는 아이디어를 이해하지 못했습니다 ...

+0

이전 매핑이 다른 시퀀스와 하나의 시퀀스가 ​​'뒤에'있었습니까? 또 다른 질문 : 다른 환경의 데이터를 복사 했습니까? 시퀀스를 복사하지 않고 모든 테이블을 마이그레이션 할 수 있기 때문입니다. – Augusto

+0

안녕하세요 Augusto, 빠른 답장을 보내 주셔서 감사합니다. 첫째, 데이터는 동일합니다. 그것은 다른 환경에서 온 것이 아닙니다. 나는 단지 테이블을 재 배열하고 떨어 뜨렸다. 또한, 매핑이 다른 시퀀스를 사용했다고 생각하지 않습니다. 새 시퀀스는 완전히 새로운 전용 시퀀스가있는 완전히 새로운 열입니다. - 한 쪽 메모 : 나는 방금 말하는 "allocationSize"설정과 우연히 만난다. 그것은 관련 될 수 있습니까? – exhuma

답변

5

확실하게 Hibernate의 경우 GenerationType.SEQUENCE를 사용하는 경우 기본값은 데이터베이스에서 반환 된 값보다ids 앞에 hi/lo 전략을 사용하는 것입니다. allocationSize를 1로 설정하면 DTRT 여야합니다.

매우 비슷한 문제에 대한 이전의 대답 : 당신의 allocationSize이 50이기 때문에 Hibernate generating two different sequence Ids for PostgreSQL insert

+0

감사합니다. 이것은 정확하게 그랬다 :) – exhuma

2

네,이, (기본값). 우리는 이클립스 링크가 next_value를한다는 것은 증가분이 50이라고 가정하기 때문에 이전 50 개의 아이디가있다.

allocationSize는 시퀀스 증가와 일치해야합니다. 시퀀스 증분 값을 50으로 업데이트하는 것이 좋습니다. 이렇게하면 시퀀스를 미리 할당하여 성능을 크게 향상시킬 수 있습니다. 그래서 당신이 생각하는 경우에 따라, 당신은 다음, 1 스틱 1

에 주석에 allocationSize을 변경하려면

나는 오랫동안 ID의를 추천하지만, INT는 4,294,967,296까지 안전합니다 당신은 당신의 응용 프로그램의 인생에서 4 십억 개 이상의 행을 갖게 될 것입니다.

+0

4billion ...이 경우에는 매우 의심 스럽다. 지난 25 년 동안, 그것은 단지 약 15k 행을 축적했다. 그리고 정상화로 인해 이것은 상당히 삭감되어야합니다. – exhuma

관련 문제