연관성이 있는 두 테이블이 동일한 유니크 조건을 가지고 있으나

다른 복합키 설정이되어있으며 관계도를 형성하는 외래키설정을 무시했을때


두가지 상황으로 볼수 있습니다.

  • 설계상의 문제 : 무결성을 지킬필요가 있어 외래키가 설정이 요구되나, 무시한경우
  • 의도된 상황 : 무결성을 지킬필요없는 로그성및 통계성


관련 영문 키워드 :

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(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);			
		});		
	}

조인문을 사용하지않고(실제는 조인문이 발생함), 각각의 다른테이블에 존재하는

아이템정보와 아이템통계의 참조를 얻어서 뷰카운트를 객체지향적 방법으로 조회를 하였습니다.

사용된 데이터>

ItemInfoItemStatics


결과>

T1 100
T2 200
T3 200




  • No labels