연관성이 있는 두 테이블이 동일한 유니크 조건을 가지고 있으나 다른 복합키 설정이되어있으며 관계도를 형성하는 외래키설정을 무시했을때 두가지 상황으로 볼수 있습니다.
관련 영문 키워드 : mapping compositekey primary and non forign |
유니크 : itemono + itemtype 은 두 연관테이블에서 각각 고유한 식별값이라고 가정합니다.
CREATE TABLE `db_example2`.`iteminfo` ( `itemtype` CHAR(1) NOT NULL, `itemno` INT NOT NULL, `itemname` VARCHAR(45) NULL, PRIMARY KEY (`itemtype`, `itemno`)); |
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에서도 중요하며 어플리케이션에서는 검색시 이러한 해시조건이 복잡해진다고 좋을것이 없기때문입니다. |
import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class ItemId implements Serializable { @Column(columnDefinition="char(1)") //특수데이터 데이터 Type 변환방법 char(1) -> string 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); }); } |
조인문을 사용하지않고(실제는 조인문이 발생함), 각각의 다른테이블에 존재하는 아이템정보와 아이템통계의 참조를 얻어서 뷰카운트를 객체지향적 방법으로 조회를 하였습니다. 사용된 데이터>
결과> T1 100 |