더미데이터를 작성하던 도중 겪었던 문제를 포스팅 하려고합니다.

 

우선 save는 JpaRepository에 내장되어있는 메소드입니다.

save가 수행하는 작업은 insert와 update 이렇게 두가지입니다.

insert와 update로 나뉘는 기준은 select를 했을 때 PK가 있으면 update, 없으면 insert입니다. (물론 null이어도 insert입니다.)

 

우선 User Entity를 작성합니다.

PK는 id이고 auto_increment 속성을 추가하였습니다.

 

그리고 UserRepository를 생성만 해줍니다.

어차피 JpaRepository 내장메소드인 save를 사용하므로 내용은 없습니다.

 

그리고 UserRepository에 대한 Test를 작성해주고 실행합니다.

 

어? save를 두번했으니 2L아닌가요??

심지어는 두번째로 save한 데이터로 덮어져 있습니다.

 

sql문 실행 로그를 확인해보았더니 insert를 했다가 update를 합니다.

 

사실 확인을 위해 save이후의 id를 확인해보았습니다.

 

여기서 insert 직후 id가 1로 출력이 되었습니다.

save(user)를 하였는데 user에 자동으로 insert된 row가 저장되는 모양입니다.

 

이를 해결하기 위해서는 두 번째 save를 하기 전에 id를 null로 바꿔주어야합니다.

user.setId(null);을 추가합니다.

 

이제 insert가 두 번 되었음을 확인할 수 있습니다.

 

db에도 잘 들어갔네요!

 

save를 하면 Entity 객체에 자동으로 값이 들어간다는 사실을 몰라서 겪었던 상황이었습니다.

@GeneratedValue는 @Id와 함께 쓰는 어노테이션이며 auto_increment와 같은 자동 생성 전략을 결정합니다.

 

JPA에서 복합키를 구현하기 위한 IdClass와 EmbeddedId를 복습하던 도중 @GeneratedValue도 함께 사용해보았습니다.

 

IdClass 사용

우선 Primary Key를 위한 UserId 클래스를 생성합니다.

 

그리고 User Entity를 생성합니다.

클래스선언 위에 @IdClass를 사용해줍니다.

 

이제 DB가 만들어지는지 실행을 해볼까요?

음~ 잘 만들어졌네요!

 

이제 User table에 데이터를 넣어봅시다.

데이터를 넣기 위해 Test를 작성하였습니다.

User 테이블은 auto_increment이므로 id는 1이됩니다.

 

하지만 에러가 떠버립니다.

 

 

EmbeddedId 사용

다음은 Embeddable 입니다.

우선 Primary Key를 위한 UserId 클래스를 생성합니다.

 

그리고 User Entity입니다.

PK 위에 @EmbeddedId를 사용합니다.

 

이번에는 auto_increment조차 생기지 않습니다.

다른 방법들도 시도해보았으나 모두 실패했습니다 ㅠ

 

 

결론

사실 제가 코드를 잘못 짠줄 알고 구글링을 여러번 시도했습니다.

https://infondgndg91.blogspot.com/2019/11/hibernate-composite-identifiers.html

 

Hibernate - Composite Identifiers @EmbeddedId @IdClass With @GeneratedValue is impossible

ndgndg91

infondgndg91.blogspot.com

그러던 중 이 블로그를 발견하였고, 이분도 어떤 커뮤니티에서 물어보셨던 것인지

@GeneratedValue를 @IdClass, @EmbeddedId와 함께 사용하는 것이 불가능하다는 답변을 받은것 같습니다.

 

앞으로 주의해서 사용해야 할 것 같습니다.

복합 키를 구현하기 위해서 두 가지 방법을 이용할 수 있습니다.

  1. IdClass 어노테이션 이용
  2. Embeddable 어노테이션 이용

IdClass 어노테이션은 https://emoney96.tistory.com/249 에 정리가 되어있으며,

이 글에서는 Embeddable 어노테이션 적용'만' 다룰 것입니다.

 

우선 @Embeddable을 적용할 Id전용 클래스를 생성합니다.

@IdClass와 다른 점은 @Embeddable을 붙인다는 점밖에 없습니다.

FollowId 클래스를 생성합니다.

 

Follow Entity 클래스에서 EmbeddedId 어노테이션을 적용한 FollowId 클래스 변수를 선언합니다.

 

그 다음 @MapsId 어노테이션을 이용하여 FollowId의 각 변수들과 매핑시켜주시면 됩니다.

여기서 주의할 점은

User 클래스에서 작성한 mappedBy의 이름과 Follow의 변수명이 같아야하고,

Follow 클래스에서 작성한 MapsId의 value와 FollowId의 변수명이 같아야합니다.

 

FollowId의 변수 fan을 fan1으로 변경했을 경우에도 실행은 됩니다.

하지만 table은 의도한대로 만들어지지 않는 것을 알 수 있습니다.

위의 결과는 fan1은 외래 키가 아니라 follow table의 순수 컬럼이자 기본 키가 되는 것이고,

fan은 외래 키가 맞지만 FollowId 클래스에 매핑할 "fan" 변수가 없어서 기본 키가 되지 못한 상황입니다.

 

 

복합 키를 구현하기 위해 @Id 어노테이션을 두개 사용했더니 에러가 발생했습니다 ㅠ

 

구글링 하다가 @Id를 한 클래스에 두개를 쓰면 안된다는 것을 알게되었고 복합 키 구현 방법을 찾아다녔습니다.

 

일단 복합 키 구현에는 두 가지 방법이 있습니다.

  1. IdClass 어노테이션 이용
  2. Embeddable 어노테이션 이용

저는 이 글에서 IdClass 어노테이션 적용'만' 다룰 것입니다.

(Embeddable은 몰라서 그래요.. 공부해서 포스팅 해보겠습니다...)

 

 

우선 @IdClass를 적용하기 위해 Id전용 클래스를 생성합니다.

저는 FollowId 클래스를 생성하였습니다.

 

그 다음 Entity 클래스에서 IdClass 어노테이션을 추가해서 작성해둔 Id전용 클래스를 적어두면 끝입니다!

 

여기서 주의할 점은

User 클래스에서 작성한 mappedBy의 이름과 Follow의 변수명, FollowId의 변수명

이 세가지가 모두 같아야합니다!

'Spring' 카테고리의 다른 글

Entity @GeneratedValue with @IdClass, @EmbeddedId  (2) 2021.08.06
Entity @Embeddable을 이용한 복합 키 구현  (0) 2021.08.01
Spring @RequestParam String[] 문제  (0) 2021.07.24
Spring JPA Pagenation  (0) 2021.07.24
Spring Optional.isPresent()  (0) 2021.07.15

+ Recent posts