PRIMARY KEY와 UNIQUE KEY 차이점을 막상 얘기하라고 하면 나에게는 조금 헷갈렸기 때문에

공부후에 내가 생각하는 결정적 차이점을 얘기해보려 한다. 

 

PRIMARY KEY(기본키)

-테이블 데이터를 구분짓는 ID에 사용하는 키

-NULL값을 허용하지 않는다. NOT NULL로 반드시 값을 입력해야 한다.

-값이 중복되지 않는다.

 

-예를들어 ID_NO는 PRIMARY KEY이다.

 컬럼 ID_NO가 있다면 ID_00000 과 같은 데이터라고 볼 수 있다.

 

UNIQUE KEY(고유키)

-중복되지 않아야 하는 데이터(데이터만이 가지고 있는 유일한 정보 : 주민번호)에 사용하는 키

-NULL값 허용

-값이 중복되지 않는다.

 

문제상황

 

1.RealMember 클래스이름을 다시 기억하기 쉽게 Member이름으로 변경(테스트용 Member클래스파일은 바로삭제)

연동되는 클래스파일이름을 RealMember로 안해주고 그냥 Member를 사용한상태로 테이블을 생성했었었다.

그리고, 다시 기존 Member 클래스파일을 지우고 RealMember 클래스파일 이름을 MemberRENAME으로 바꿔주었다.

 

2. 의문점

이미 한번 과거 Member 안에 작성된 코드를 이용해서 생성된 테이블 을 한번 만들어줬다가

이름만 바꿔서 코드내용 바꿔주어서 다시 생성하면 변경된대로 적용되는지 궁금하다.

 

3. 디비 h2 맞고, 연동도 되어 있다.

H2 데이터베이스 콘솔접속해서 테이블들을 확인해보니 RealMember는 그대로 있고 Member도 그대로 있다.

테이블에서는 영향을 미치지않아 내가 직접 drop해주어야 하는 건지 모르겠다.

 

문제해결시도과정

1. 이름이 변경된 Member클래스에서 Member를 import 설정

Build completed with 2 errors and 0 warnings in 11 s 105 ms

빌드하는 과정에서 에러가 두가지 있었는데 Memberimport를 해주었다.

바로 밑에 코드 에도 (Member)로 설정

 

 

2.초기화옵션 ddl-auto:create, 데이터베이스에서 기존 Member 테이블 삭제시도

 

사진

 

ddl-auto:create옵션인 상태에서 h2 데이터베이스 접속해서 기존 MEMBER 테이블 삭제하려고 하니

다음과 같은 에러가 나온다.

------------------------------------------------------------------------

Cannot drop "MEMBER" because "FKPKTXWHJ3X9M4GTH5FF6BKQGEB" depends on it; SQL statement:

DROP TABLE member [90107-200] 90107/90107 (도움말)

org.h2.jdbc.JdbcSQLSyntaxErrorException: Cannot drop "MEMBER" because "FKPKTXWHJ3X9M4GTH5FF6BKQGEB" depends on it; SQL statement:

DROP TABLE member [90107-200]

at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)

at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)

at org.h2.message.DbException.get(DbException.java:205)

at org.h2.command.ddl.DropTable.prepareDrop(DropTable.java:98)

at org.h2.command.ddl.DropTable.update(DropTable.java:124)

at org.h2.command.CommandContainer.update(CommandContainer.java:198)

at org.h2.command.Command.executeUpdate(Command.java:251)

at org.h2.server.TcpServerThread.process(TcpServerThread.java:406)

at org.h2.server.TcpServerThread.run(TcpServerThread.java:183)

at java.lang.Thread.run(Unknown Source)

 

at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)

at org.h2.engine.SessionRemote.done(SessionRemote.java:611)

at org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:237)

at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:228)

at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201)

at org.h2.server.web.WebApp.getResult(WebApp.java:1459)

at org.h2.server.web.WebApp.query(WebApp.java:1116)

at org.h2.server.web.WebApp$1.next(WebApp.java:1078)

at org.h2.server.web.WebApp$1.next(WebApp.java:1065)

at org.h2.server.web.WebThread.process(WebThread.java:178)

at org.h2.server.web.WebThread.run(WebThread.java:94)

at java.lang.Thread.run(Unknown Source)

------------------------------------------------------------

 

-여기에서 내가 확인하고 이해한 에러 핵심은 다음과 같다.

-일단 MEMBER 테이블을 삭제할 수 없다. 그리고 Unknown Source 알려지지 않은 소스 Cannot drop "MEMBER"....

.

.

at java.lang.Thread.run(Unknown Source)

 

-기존에 MEMBER클래스파일을 삭제해서 테이블에서도 찾아내지 못해 삭제하지 못하는 것이라는 가설을 세웠다.

 

2. Real_Member 테이블 삭제 시도

-DROP TABLE Real_Member;

-지워진다..

-이것은 Real_Member 이름을 가진 클래스파일을 인식해서인지 삭제가 되었다.

-다시 h2 데이터베이스 재접속 상황은 같다.

 

3. 기존 MEMBER 클래스 파일을 다시 만들어서 삭제한다?

-이미 RealMember클래스파일 이름을 MEMBER파일로 바꾸었는데 다시 만들어서 테이블삭제는 말이 안되었다.

이미 변경한 MEMBER클래스파일은 어떻게 한단 말이지..

 

4. 테이블삭제시도전에 코드를 run하는 과정에서 drop if exists 문구와 error executing ddl를 확인한 것이 기억났다.

 

출처 https://galid1.tistory.com/610

구글링 해보니, 초기화 옵션을 (ddl-auto: update)update로 해주면 에러가 해결된다는 내용이 있었다.

물론 나와는 상황이 조금 달랐지만, 혹시 테이블도 update 되지 않을까 하는 생각으로 변경해주고 다시 테이블 설정을 했다.

 

 

결과는 클래스파일 RealMember에서 RENAME으로 변경한 Member클래스파일에 작성된 컬럼들이 생성됨을 확인했다. 즉 새롭게 변경해준 Member클래스파일 내용으로 update가 되었다.

 

5.기존에 있던 ID, USERNAME은 그대로 존재한다. 기존에 있는 컬럼에 합쳐진 것 같다.

 

맴버테이블을 연관관계없이 생성한 상태일 때에 삭제가 안될 수도 있다고 하여,

기존 멤버테이블 컬럼삭제된 상태에서, 테이블을 삭제 시도 해보았다.

 

하기와 같은 명령어를 이용해 ID, USERNAME을 삭제했다.

ALTER TABLE MEMBER

DROP COLUMN USERNAME;

 

삭제가 되어 현재 변경된 Member클래스 내용과 동일한 내용으로 업데이트하여 해결완료!

 

7.이왕 삭제하는 김에 테이블전부 삭제하고 다시 생성하기로 했다. (ddl-auto : create)

 

*맴버테이블을 연관관계없이 생성한 상태일 때에 삭제가 안될 수도 있다고 하여,

만약 연관관계가 있는 상태에서 삭제가 되지 않는다면 하기 명령어로 해볼 것

 

DROP TABLE : 테이블의 모든 데이터 및 구조를 삭제

-DROP TABLE 테이블명 [CASACADE CONSTRAINT];

 

기타공부내용

기타해결방법(기존 member 클래스파일을 realmember로 변경할 경우에 사용할 것)

-삭제된 member는 이제 더 이상 jpa가 관리하는 persist에 의해 영속성을 가지지 못하고

그냥 orm과는 관계 없고, 자바와는 관계없는 분리된 db테이블이 됨

더 이상 사용되지 않는 테이블이 되었다.

 

ddl-auto : create (ddl-auto옵션은 create)

멤버랑 리얼멤버 테이블을 drop시키고 다시 테이블을 새로 생성해도 무방하다.

의존성을 가진다면 테이블 스페이스를 전체를 다 날려버리면,

스프링이 재시작 될 때에 처음부터 다시 전체 테이블을 만들어줄 것이다.

바뀐 멤버엔티티에 영속성이 걸리게 되고, 연관관계매핑도 작성된대로 설정이 된다.

 

이해를 위한 ddl-auto : create옵션 추가설명

-예를들어, jpashop이라는 폴더를 만들고 그안에 member라는 폴더를 만들고 파일도 있다.

근데 이름을 realmember로 바꾸려하면 create 옵션은

기존 member는 그대로 냅두고 realmember폴더를 새로 만드는 것과도 같다.

1.3 회원테이블분석

Member 테이블

Member_ID

NAME

|CITY : VALUE TYPE/임베디드 타입 그대로 필드로 내려온 것이다.

|STREET : VALUE TYPE/임베디드 타입 그대로 필드로 내려온 것이다.

|ZIPCODE : VALUE TYPE/임베디드 타입 그대로 필드로 내려온 것이다.

 

설명

-1:1 맵핑이다.

-이름과 임베디드 타입인 주소(Address), 그리고 주문(orders) 리스트를 가진다.

 

Delivery 테이블

Delivery_ID

STATUS

CITY : VALUE TYPE/임베디드 타입 그대로 필드로 내려온 것이다.

STREET : VALUE TYPE/임베디드 타입 그대로 필드로 내려온 것이다.

ZIPCODE : VALUE TYPE/임베디드 타입 그대로 필드로 내려온 것이다.

 

설명

-회원 엔티티의 Address 임베디드 타입 정보가 회원 테이블에 그대로 들어갔다.

이것은 DELIVERY 테이블도 마찬가지다.

 

ITEM 테이블

ITEM_ID(상품 ID)

-상속관계 맵핑 기본편에서 설명한 3가지 전략중 가장 단순한 싱글테이블 전략을 사용했다.

 싱글테이블전략은 한테이블에 DTYPE으로 구분해서 다 넣는다.

 일반적으로 성능이 잘 나온다.

-단점이라하면 필드에 ARTIST,ETC,AUTHOR,ISBN,DIRECTOR,ACTOR 전부 섞여서 싱글테

 이블에 들어간다.

-앨범, 도서, 화 타입을 통합해서 하나의 테이블로 만들었다. DTYPE 컬럼으로 타입을 구분한

 다.

 

Orders 테이블

ORDER_ID (주문 ID)

MEMBER_ID (Foreign Key, 회원 ID)

DELIVERY_ID (Foreign Key, 배송 ID)

 

참고

-테이블명이 ORDER가 아니라 ORDERS인 것은 데이터베이스가 order by 때문에 예약어로 잡고 있는 경우가 많다.

 그래서 관례상 ORDERS를 많이 사용한다.

 

주문상품테이블

주문상품 ORDER_ITEM

ORDER_ITEM_ID

ORDER_ID (FK)

ITEM_ID (FK)

ORDERPRICE (주문한 상품가격)

COUNT (주문한 상품 개수)

 

카테고리(CATEGORY)

CATEGORY_ID

PARENT_ID (FK)

NAME

CATEGORY_ITEM

CATEGORY_ID (FK)

ITEM_ID (FK)

 

설명

-객체에서는 카테고리가 아이템리스트를 가져도 되고

아이템이 카테고리리스트를 가져도 된다.

양쪽 컬렉션을 만들면 객체는 다대 다로 만들 수 있지만

관계형데이터베이스는 일반적 설계로는 그렇게 할 수 없다.

중간에 매핑 테이블(CATEGORY_ITEM)을 두어,

1(CATEGORY) (CATEGORY_ITEM) 관계 및 다대(CATEGORY_ITEM) 1(ITEM)로 풀어

낸다.

 

참고

*강의에서는 객체를 구분하기 위해 DB에 대문자를 사용했다.

-실제 코드에서는 DB에 소문자 + _(언더스코어) 스타일을 사용하겠다.

-데이터베이스 테이블명, 컬럼명에 대한 관례는 회사마다 다르다.

 보통은 대문자 + _(언더스코어)나 소문자 + _(언더스코어) 방식 중에 하나를 지정해서

 일관성 있게 사용한다. 강의에서 설명할 때는 객체와 차이를 나 타내기 위해 데이터베이스

 테이블, 컬럼명은 대문자를 사용했지만, 실제 코드에서는 소문자 + _(언더스코 어) 스타일을

 사용하겠다.

 

2-1. 도메인모델과 테이블 설계

a.회원, 주문, 상품의 관계

-회원은 여러 상품을 주문할 수 있다. 그리고 한 번 주문할 때 여러 상품을 선택할 수 있기에 주문과 상품은 다대다 관

-하지만 이런 다대다 관계는 관계형 데이터베이스는 물론이고 엔티 티에서도 거의 사용하지 않는다.

-따라서 그림처럼 주문상품이라는 엔티티를 추가해서 다대다 관계를 일대 다, 다대 일 관계로 풀어냈다.

 

상품 분류

-상품은 도서, 음반, 화로 구분되는데 상품이라는 공통 속성을 사용하므로 상속 구조로 표현했 다.

 

b.회원과 주문 관계

-회원은 여러 주문을 할 수 있어서 회원과 주문의 관계는 1대 다의 관계이다.

 

c.회원과 주문, 주문과 상품 관계

-회원이 한번 주문할 때 여러개의 상품을 주문할 수 있다.

-상품도 여러 주문에 담길 수 있으면 다대 다 관계가 된다.

-하지만 이런 다대다 관계는 관계형 데이터베이스는 물론이고 엔티티에서도 거의 사용하지 않는다.

-그래서 1대 다 다 대 1의 관계 관계로 만들기 위해

 그림처럼 주문상품(테이블+주문수량)이라는 엔티티를 추가해서 다대다 관계를 일대 다,

 다대일 관계로 풀어냈다.

 

d.주문과 배송정보

-11 관계

-주문할 때 배송정보를 입력할 수 있도록 해놓음

 

e.상품

-도서, 음반, 영화 로 타입이 나누어짐

 

f.상품과 카테고리

-상품은 카테고리에 매핑이 된다.

-하나의 카테고리에 여러 가지 상품이 들어갈 수도 있고,

 어떤 상품이 카테고리에 복수로 들어갈 수 있기 때문에

 다대 다 관계로 세팅

 

g.데이터베이스의 목적

(참고 블로그 http://kdskor.blogspot.com/2010/10/pk-fk.html)

-효율적이고, 성능면에서 매우 편리하며 신속하게 수많은 데이터들을 보관 및 관리하는 것

-그 중에서도 제일 우선시 되어야 하는 것이 데이터의 무결성이다.

 신속하게 처리한다 하더라도 데이터에 결점이 있다면 데이터는 쓸모가 없을 뿐 아니라,

 데이터의 결점으로 인하여 잘못된 결과를 초래

-데이터 무결성을 보장해주기 위해서 가장 기본적으로 필요한 것이 PKFK

 

h.PK(Primary Key)FK(Foreign Key)

PK

-데이터베이스 생성에서 가장 기본적으로 고려되는 것이 PK

-PK만큼 중요한 것이 FK

-PK는 테이블에서 오직한개만 존재

-PK가 데이터의 유일성을 보장

-테이블에서 PK를 조건으로 조회하여 한 개의 값만 나오거나 값이 나오지 않게 됨

 

FK

-외래 키는 참조하는 테이블에서 1개의 키(속성 또는 속성의 집합)에 해당하고,

 참조하는 측의 관계 변수는 참조되는 측의 테이블의 키를 가리킨다.

-관계형 데이터베이스에서 외래 키(외부 키, Foreign Key)는 한 테이블의 필드(attribute) 중 다른 테이블의 행(row)

 식별할 수 있는 키

 

)아파트테이블 세대테이블의 아파트코드값에

   아파트테이블의 아파트코드에 없는 값이 들어간다면?

   이 때 데이터를 저장 또는 수정시 아파트코드 데이터는 아파트 테이블에 있는 아파트코드

   가 맞는지 확인해야 하는데, 이것이 자동적으로 확인되도록 도와주는 것이 FK이다.

1. resources -> templates -> application.yml생성

yml 또는 properties를 사용하면 된다.

설정파일이 복잡해지면 yml이 더낫다.

여기에서는 application.yml을 생성하고

기존에 있던 application.properties삭제 한다.

 

*YAML이란 (위키백과 참고)

- XML, C, 파이썬, , RFC2822에서 정의된 e-mail 양식에서 개념을 얻어 만들어진

  '사람이 쉽게 읽을 수 있는' 데이터 직렬화 양식

-XMLJSON이 데이터 직렬화에 주로 쓰이기 시작하면서,

 많은 사람들이 YAML'가벼운 마크업 언어'로 사용하려 함

 

*PROPERTIES이란 (위키백과 참고)

-응용 프로그램의 구성 가능한 파라미터들을 저장하기 위해

 자바 관련 기술을 주로 사용하는 파일들을 위한 파일 확장자

-더 복잡한 설정 포맷을 원할 경우 XMLYAML이 사용된다.

 

2. Database connection : 데이터베이스 소스 설정

a. spring 세팅

datasource :

  url: (상기사진내용참고)

  username: sa

  password: 

  driver-class-name: (상기사진내용참고)

(주의: 칸 띄어쓰기가 제대로 되어 맞춰지지 않는다면 테스트시 에러발생할 가능성이 크다!!)

 

설명

application.yml 안에

하기와 같이 설정하게 되면

데이터베이스 연결과 관련된 데이터소스설정이 완료 된다.

[url: jdbc:h2:tcp://localhost/~/jpashop;MVCC=TRUE]

 

*MVCC TRUE

-> 여러개가 접근할 때 조금 더 빨리 처리가 된다. 넣어주는 것이 권장.

*스프링부트에서 hikaricp를 써서 데이터베이스 커넥션 풀 등 위의 세팅이 이루어지게 한다.

 

b. JPA 세팅

 hibernate:

  ddl-auto: create

 properties:

hibernate:

 #show_sql: true

    format_sql: true

 

*createtab을 자동생성해주는 역할을 한다.

application 실행시점에 내가가지고 있는 엔티티(테이블)정보를 전부 다 지우고,

다시 생성한다.

*properties (*hibernate와 관련된 특정한 properties 사용할 것을 여기에다가 타입한다.)

*설정하는 것을 어떻게 배우느냐

spring bootreference document를 참고해서 하나하나씩 공부해야 한다.

https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/

Data Access ->configure JPA Properties를 찾아서 읽어볼 것!

 

c. LOG LEVEL세팅

logging:

   level:

    org.hibernate.SQL: debug

 

(주의 : 잘 안될 경우, logging.level:로 세팅할 것!)

 

*hibernate.SQLdebug모드로 사용한다는 의미가 있고,

jpahibernate가 생성하는 SQL전부 확인이 가능하다.

 

show_sqlorg.hibernate.SQL의 차이점

jpa:

show_sql: true

->system.out에 출력하는 것. 그래서 주석처리를 하여 사용하지 않도록 한다.

운영환경에서는 사용하지 않는다.

 

logging:

org.hibernate.SQL: debug

->log on을 통해 출력하는 것. 운영환경에서는 로그들을 log on을 통해 출력해야 한다.

 

+ Recent posts