1년 전 진행했던 마실가실 프로젝트를 🛠️리팩토링하며 정리한 내용입니다.
애플리케이션 껐다키면 userId가 50 증가한 썰..
Spring Security를 전체적으로 리리팩토링을 하고 Postman으로 전체적인 동작을 확인하고 있습니다.
그러다 문득, DB에서 UserId값을 보는데, 2000번을 넘었더라고요.
내가 Create 메서드를 2000번이나 했으려나..? 라는 생각과 함께 Postman으로 Id값이 제대로 증가하는지 확인해보다 애플리케이션을 껐다 키면 50이 증가해버리는 문제를 발견했습니다.
간단하게 고쳐보는 과정을 남겨봅니다..
Hibernate5부터 MySQL DB로 @GeneratedValue를 사용해서 AUTO를 strategy로 선택하게 되면, GenerationType.TABLE이 선택됩니다.
이 때, 애플리케이션을 껐다가 다시 실행하면 값이 50씩 증가하는 이유는 Hibernate가 테이블 기반 시퀀스를 사용하는데, 기본적으로 증가 단위를 50으로 설정하기 때문입니다. 이는 성능을 위해서 미리 ID를 확보해 놓는 방식이며, 애플리케이션이 종료되면 캐시된 ID들이 사라져서 다음 시작 시 새로운 ID 할당이 시작됩니다.
이를 해결하기위해서는 allocationSize를 명시적으로 지정하면 됩니다.
User.java
@Entity
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "my_table_generator")
@TableGenerator(name = "my_table_generator", allocationSize = 1)
@Column(name = "user_id")
private Integer id;
}
이렇게 하면 해결은 되는데, 문제는 TABLE 전략을 사용하는 것에 대해 고민을 해봐야 한다는 것입니다..
왜냐면, Table 전략은 모든 Table들이 하나의 Sequence 테이블을 두고 사용하는 전략인데
1. 여러 트랜잭션이 동시에 ID를 할당받으려 하면 ID 테이블에 대해 잠금(lock)이 발생할 수 있고,
2. TABLE 전략을 사용할 때는 allocationSize와 같은 설정을 최적화해야 하는데, 그렇지 않으면 ID 증가 단위가 크거나, 중간에 간격이 생기는 등 예상치 못한 문제들이 (저처럼;;) 발생할 수 있기 때문입니다.
이에 반해 Identity 전략은 DB에서 직접 ID를 할당하는 방식인데, MySQL의 경우 AUTO_INCREMENT 기능을 사용합니다.
ID 생성 시 별도의 테이블 접근이 필요하지 않으므로, 성능 상의 이점이 있습니다.
또한, 추가 설정 없이 MySQL의 기본 기능을 사용하기 때문에, 설정이 복잡하지 않고 유지보수도 상대적으로 간단합니다.
따라서 MySQL에서는 성능과 관리 효율성 측면에서 @GeneratedValue(strategy = GenerationType.IDENTITY)를 사용하는 것이 일반적으로 권장됩니다.
User.java
@Entity
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Integer id;
}
🚨 Auto Increment를 사용하기 때문에 MySQL에서 userId값에 해당 설정이 추가되어 있어야 합니다.
또한, 기존에 사용했던 Id값보다 +1 값부터 증가시켜줘야 하므로, 추가적인 설정이 필요합니다.
-- AUTO_INCREMENT 추가
ALTER TABLE user MODIFY user_id INT NOT NULL AUTO_INCREMENT;
-- 외래키 조건이 있을 경우, 임시 삭제
ALTER TABLE trip DROP FOREIGN KEY 외래키_이름;
-- 외래키 재설정
ALTER TABLE trip
ADD CONSTRAINT 외래키_이름
FOREIGN KEY (user_id) REFERENCES user(user_id);
-- AUTO INCREMENT 시작 번호 지정
ALTER TABLE user AUTO_INCREMENT = 기존_USERID보다_1_더_큰_값;
🙋♀️
본 포스트는 공부 목적으로 작성하였습니다.
보시는 도중 잘못된 부분이나 개선할 부분이 있다면 댓글로 알려주시면 수정하도록 하겠습니다.
📑
참고 자료
https://dev-box.tistory.com/101#google_vignette
'PlayGround > 마실가실 리팩토링' 카테고리의 다른 글
[1년 후 마실가실] SonarQube와 Immutable List (0) | 2024.11.22 |
---|---|
[1년 후 마실가실] ExceptionHandlerFilter (0) | 2024.11.17 |
[1년 후 마실가실] CharacterEncodingFilter (4) | 2024.11.10 |
[1년 후 마실가실] Spring Security + JWT - Header (0) | 2024.11.03 |
[1년 후 마실가실] Spring Security + JWT - LoginFilter (0) | 2024.10.27 |