JPA도 복합키(Composite Key)가 가능할까?
PlayStore에서 자사 앱 제품들에 대해 Selenium을 이용하여 앱 정보들을 크롤링후 DB에 저장하는 프로그램을 개발하던중 복합키가 필요하게 되었다.
기존 강의에서는 단일키를 Primary Key로 설정해서 복합키 생성은 처음이었다. 하지만 막상 해보니 이해는 잘 갔다. 역시 짬을 내서 따로 더 공부를 해야겠다...
아래는 앱 버전을 따로 관리하는 VersionInfo Entity다. 잘 살펴보면 @EmbeddedId 어노테이션이 처리된 칼럼이 있다. @EmbeddedId는 @Embeddable 처리된 VersionId를 Primary Key로 갖게 해주는 기능을 한다. 즉 VersionId에 존재하는 칼럼들을 Primary Key로 갖게 해주는 것 이다. 따라서 appName, version을 Primary Key로 갖는 Entity가 되는 것 이다.
@Entity
@Getter
public class VersionInfo implements Serializable {
@EmbeddedId
private VersionId versionId;
@Column(name = "UpdatedDate")
private String updatedDate;
private LocalDateTime createdDate;
private LocalDateTime modifiedDate;
public void setCreatedDate(){
LocalDateTime now = LocalDateTime.now();
createdDate = now;
modifiedDate = now;
}
public VersionInfo() {
}
public VersionInfo(VersionId versionId, String updatedDate) {
this.versionId = versionId;
this.updatedDate = updatedDate;
}
}
@Embeddable
@Getter
@Setter
public class VersionId implements Serializable {
private String appName;
private String version;
public VersionId(String appName, String version) {
this.appName = appName;
this.version = version;
}
public VersionId() {
}
}
실제로 잘 작동하는지 확인을 위해 해당 테스트를 2번 실행해봤다.
@Test
@Transactional
@Rollback(value = false)
public void versionTest(){
String[] arr = {"com.shinhan.sbanking", "com.shinhan.smartcaremgr", "com.shinhan.sbankmini"};
List<HashMap<String, String>> listInfos = crawler.getInfoList(arr);
for (HashMap<String, String> infos : listInfos) {
System.out.println("===========================\n");
String appName = infos.get("앱 이름");
String version = infos.get("버전");
String updatedDate = infos.get("업데이트 날짜");
updatedDate = updatedDate.replaceAll(" ","");
updatedDate = updatedDate.substring(0, updatedDate.length()-1);
VersionId versionId = new VersionId(appName, version);
versionInfoRepository.save(new VersionInfo(versionId, updatedDate));
System.out.println("===========================\n");
}
}
그랬더니 아래와 같은 에러가 나오며 테스트가 종료되었다.
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PUBLIC.PRIMARY_KEY_8 ON PUBLIC.VERSION_INFO(APP_NAME, VERSION) VALUES 1"; SQL statement:
insert into version_info (created_date, modified_date, updated_date, app_name, version) values (?, ?, ?, ?, ?) [23505-212]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
즉 중복된 키로 인해 DB에 insert를 할 수 없다는 것이다. 정상 작동을 확인 할 수 있었다..!