연관성이 있는 두 테이블이 유니크한 복합키로 지정이 되어 있으며
관계도를 형성하는 외래키 설정이 없을때
두가지 상황으로 볼수 있습니다.
- 설계상의 문제 : 무결성을 지킬필요가 있어 외래키가 설정이 요구되나, 무시한경우
- 의도된 상황 : 무결성을 지킬필요없는 로그성및 통계성
관련 영문 키워드:
mapping compositekey primary and non forign
샘플 DDL
유니크 : itemono + itemtype 은 두 연관테이블에서 각각 고유한 식별값이라고 가정합니다.
ItemlInfo
CREATE TABLE `db_example2`.`iteminfo` ( `itemtype` CHAR(1) NOT NULL, `itemno` INT NOT NULL, `itemname` VARCHAR(45) NULL, PRIMARY KEY (`itemtype`, `itemno`));
ItemStatics
CREATE TABLE `itemstatics` ( `itemtype` char(1) NOT NULL, `itemno` int(11) NOT NULL, `viewcnt` int(11) DEFAULT NULL, `salecnt` int(11) DEFAULT NULL, `statictype` varchar(45) NOT NULL, PRIMARY KEY (`itemtype`,`itemno`,`statictype`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
ItemStatic에서도 itemtype와 itemno둘만으로 유니크하기때문에 둘만 걸어도 되지만,3개가 걸려있습니다.
성능계에서는 클러스터인덱스의 효과를보기위해 실제 추가 키로 거는경우도 있습니다.
하지만 대부분 데이터량과 선택도를 고려하지않고 무부분별하게 걸려있는 경우가 많으며
JPA에서는 실제 유니크키한 값을, 엔티티를 구분하는 논리적인 값으로 사용하고
ItemId(itemtype,itemno) 만을 정의하여, 조인 전략을 사용할것입니다.
동일한 엔티티를 판별하는 해시체크는 JPA에서도 중요하며 어플리케이션에서는 검색시 이러한 해시조건이
복잡해진다고 좋을것이 없기때문입니다.
Entity 설계
복합키정의
import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class ItemId implements Serializable { @Column(columnDefinition="char(7)") private String itemtype; private int itemno; public ItemId() { } public ItemId(String itemtype, int itemno) { this.itemtype = itemtype; this.itemno = itemno; } @Override public int hashCode() { final int prime = 31; int result = 1; result = itemtype.hashCode() + itemno; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ItemId other = (ItemId) obj; if (itemtype == null) { if (other.itemtype != null) return false; } else if (!itemtype.equals(other.itemtype)) return false; if (itemno != other.itemno) return false; return true; } public String getItemtype() { return itemtype; } public void setItemtype(String itemtype) { this.itemtype = itemtype; } public int getItemno() { return itemno; } public void setItemno(int itemno) { this.itemno = itemno; } }
아이템통계
import javax.persistence.EmbeddedId; import javax.persistence.Entity; @Entity public class ItemStatics { @EmbeddedId ItemId staticid; int viewcnt; }
아이템정보
import javax.persistence.Column; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.ManyToOne; import javax.persistence.MapsId; @Entity public class ItemInfo { @EmbeddedId ItemId itemid; String itemname; @MapsId("staticid") //references EmbeddedId's property @JoinColumns({ @JoinColumn( insertable = false, updatable = false, name = "itemtype", referencedColumnName = "itemtype"), @JoinColumn( insertable = false, updatable = false, name = "itemno", referencedColumnName = "itemno") }) @ManyToOne private ItemStatics statics; }
조회하기(조인기능 탑재)
@Autowired ItemInfoRepository itemRepo; public void allTest() { itemRepo.findAll().forEach(item -> { String itemString = String.format("%s %d",item.getItemname() ,item.getStatics().getViewcnt() ); System.out.println(itemString); }); }