jpa 동작시 id(pk) exist 오류 발생하여 해결한 케이스.

@TableGenerator 어노테이션을 사용한 jpa 동작시 id(pk) exist 오류 발생하여 해결한 케이스를 공유합니다. 1. 문제. @TableGenerator 어노테이션을 사용한 jpa를 통해 db 데이터를 관리하였으나, jpa에서 관리하는 시퀀스 값과 db에 저장된 id(pk)값이 중복되는 이슈가 발생하였습니다. 2. 원인 @TableGenerator 어노테이션을 사용한 jpa를 사용할 경우 사용자는 allocationSize 옵션을 통해 db 시퀀스에 접근하는 횟수를 조절할 수 있습니다. 그런데 jpa로 관리되어야 하는 db 데이터를 고객사에서 쿼리를 통해 insert 한 케이스가 다수 존재하였고, jpa에서 관리되는 시퀀스 값과, 실제 db에 저장된 id(pk)가 중복되는 케이스가 발생하여 jpa를 통해 데이터를 생성하는 동작에 ID 중복에러가 발생하였습니다. 3. 해결 두가지 해결 방법이 있다고 보았습니다. 1. 서버 재기동 시퀀스 값은 결국 메모리에 저장됩니다. 따라서 해당 서버를 재기동 한다면 메모리에 저장된 데이터가 초기화 되며, db에서 시퀀스 데이터 값을 다시 가져올 것으로 예상되었습니다. 하지만 실제 운영중인 서버이며, 재기동 시에는 서비스가 이용이 불가함으로, 사용자에게 불편을 끼치게 됩니다. 사용자가 이용하지 않는 시간에 재기동을 할 경우 대기 시간이 너무 길어진다고 보았습니다. 2. transaction 단위 실행. persist()를 통해 생성된 영속성 컨텍스트는 transaction 단위로 실행됩니다. db에서 관리하는 시퀀스 값을 id와 겹치지 않도록 수정하고 api 호출을 통해 transaction을 동작시켰습니다. 이후 persist()가 동작하여 메모리 내의 값을 1씩 증가시켰으며, allocationSize 값을 모두 실행한 entityManager는 db에서 시퀀스 값을 다시 가져오게 되었고 정상적으로 동작하였습니다. allocationSize 값이 클 경우는 1번, 감당 가능할 정도라면 2번으로 선택하여 해결하면 됩니다. 번외: 1. GenerationType.TABLE일 때, allocationSize 따른 동작. ex) allocationSize = 1 일 경우 매번 시퀀스를 조회하여 pk 값을 가져옴. -> 매번 db에 접근하기때문에 성능이슈가 있습니다 ex) allocationSize = 10 일 경우 최초 persist() 실행시에 설정에 따른 db 시퀀스를 호출하여, 시작값과 끝 값을 지정합니다. 이때 시작값을 시퀀스값, 끝값을 시퀀스값 + allocationSize 로 지정하며, persist() 실행시 db에서 시퀀스를 가져오는것이 아니라 메모리에서 가상으로 관리하여 할당합니다. persist() 실행시마다 가상의 값을 1씩 증가시키며, 해당 값이 끝값과 같아지고, persist() 실행시점에 db에서 시퀀스 값을 호출하여 다시 시작값과 끝값을 지정하게 됩니다. 시퀀스를 조회하기 위해 매번 DB에 접근해야할 경우 성능이슈가 발생할수 있기때문에 적절하게 allocationSize을 설정하여 사용하는 것을 권장합니다. 2. 가볍게 보는 jpa 옵션의 값들 @GeneratedValue strategy : 어떤 방식으로 JPA 기본키를 매핑할건지 선택한다. GenerationType.IDENTITY, GenerationType.SEQUENCE, GenerationType.TABLE, GenerationType.AUTO 중에 선택가능 generator : 기본키 생성기의 이름, @TableGenerator의 name으로 사용한다 @TableGenerator name : 기본키 생성기의 이름, 보통 @GeneratedValue 사용한 generator과 동일하게 설정한다. 기본값은 없음 지정 필수. pkColumnName: 시퀀스를 관리할 테이블의 PK 컬럼의 이름을 설정한다. 기본값은 sequence_name. allocationSize : 서버에서 DB 시퀀스를 가져올 선택주기를 설정한다 EX) allocationSize =1 이면 매번 DB에서 시퀀스를 가져옴 allocationSize =10 이면 10번마다 DB에서 시퀀스를 가져옴 table : 시퀀스를 관리할 테이블 명. 기본값은 hibernate_sequences valueColumnName: 시퀀스의 마지막 값을 지칭하는 컬럼명 . 기본값은 next_val. DB에서 해당 값 조회하면 해당 시퀀스의 값을 알수있다. pkColumnValue: PK로 지정할 컬럼. 기본값은 해당 테이블의 PK. initialValue : 초기값. 마지막 생성된 값이 기준이며 기본값은 0. catalog: DB catalog 이름. schema: schema 이름 uniqueConstraints: 유니크 제약 조건을 지정. 참고한 글 : https://dololak.tistory.com/479 https://gmlwjd9405.github.io/2019/08/06/persistence-context.html https://velog.io/@gillog/JPA-%EA%B8%B0%EB%B3%B8-%ED%82%A4-%EC%83%9D%EC%84%B1-%EC%A0%84%EB%9E%B5IDENTITY-SEQUENCE-TABLE

다음 내용이 궁금하다면?

또는

이미 회원이신가요?

2023년 3월 23일 오전 7:59

조회 310

댓글 0