앱)아는만큼 보이는 데이터베이스 설계와 구축 요약2

Posted by HULIA(휴리아)
2018. 2. 21. 17:58 백엔드개발/데이터베이스
12. 데이터 독립성의 실무 적용

데이터 독립성 <-> 데이터 종속성

종속의 주체는 애플리케이션

데이터 독립성 필요이유
-유지보수비용 증가
-데이터 중복성 증가
-데이터 복잡도 증가
-요구사항 대응 저하

데이터 독립성의 핵심목적
DB에 대한 사용자의 VIEW와 DB가 실제 표현되는 VIEW를 분리하여 변경에 따른 간섭을 줄이는 것

데이터 독립성 확보시의 장점
-각 VIEW의 독립성 유지, 계층별 VIEW에 영향을 주지 않고 변경할 수 있음
-단계별 SCEMA에 따라 데이터 정의어(DDL)와 데이터 조작어(DML)가 달라짐

데이터 독립성 ANSI 표준 모델
-구조
-독립성
-사상

사용자 ->외부단계->{논리적 데이터 독립성} -> 개념적 단계 -> {물리적 데이터 독립성} -> 내부적 단계 -> DB

데이터 독립성의 구성요소
데이터 베이스 스키마 구조는 3단계로 구분되며 각각은 상호 독립적인 의미를 가지고 고유한 기능을 갖고 있다

외부 스키마(사용자관점, 접근하는 특성에 따른 스키마 구성)
-VIEW단계 여러개의 사용자 관점으로 구성
-사용자 단계로서 개개 사용자가 보는 개인적 DB 스키마
-DB의 개개 사용자나 응용 프로그래머가 접근하는 DB 정의


개념스키마(통합 관점)
-개념 단계 하나의 개념적 스키마로 구성
-모든 사용자 관점을 통합한 조직 전체의 DB를 기술하는 것
-모든 응용 시스템이나 사용자들이 필요로 하는 데이터를 통합한 조직 전체의 DB를 기술한 것으로 DB에 저장되는 데이터와 그들간의 관계를 표현하는 스키마

내부 스키마(물리적 저장 구조)
-내부단계, 내부 스키마로 구성
-DB가 물리적으로 저장된 형식
-물리적 장치에서 데이터가 실제적으로 저장되는 방법을 표현하는 스키마


논리적 독립성
-개념 스키마가 변경되어도 외부 스키마에는 영향을 미치지 않도록 지원하는 것
-논리적 구조가 변경되어도 응용 프로그램에 영향이 없음

물리적 독립성
-내부 스키마가 변경되어도 외부 스키마와 개념 스키마는 영향을 받지 않도록 지원하는 것
-저장 장치의 구조 변경은 응용프로그램과 개념 스키마에 영향이 없음

외부적/개념적 사상(논리적 사상)
-외부적 뷰와 개념적 뷰의 상호 관련성을 정의함

개념적/내부적 사상(물리적 사상)
-개념적 뷰와 저장된 데이터베이스의 상호관련성을 정의함


13. 데이터 무결성의 실무 적용
무결성을 정의할때 가장 중요한 것은 무엇으로부터의 무결성인지를 먼저 결정해야 한다는 것
-> 무결성을 지키려 할때 무결성을 요구하는 주체가 무엇이냐를 먼저 결정해야 한다는 의미

구축하고자 하는 비즈니스의 무결성이다

데이터베이스 설계시 데이터 무결성을 설계하지 않을 경우 문제점
-데이터베이스 테이블에 중복된 데이터가 존재할 수 있게 된다
-참조 무결성 제약 조건에 의해 지켜져야 할 부모와 자식 데이터의 논리적인 관계가 깨지게 된다
-컬럼 무결성 제약 조건에 의해 지켜져야 할 컬럼의 기본값, NULL 값 등이 비정상적으로 데이터베이스에 존재하게 된다


데이터 무결성 : 데이터의 정확성과 일관성이 보장된 상태

데이터 무결성의 종류
-엔티티 무결성:한 엔티티는 중복과 누락이 있을수가 없음. 즉 동일 PK를 가질수 없거나, PK의 속성이 NULL을 허용할 수 없음
-참조 무결성:FK가 참조하는 다른 개체의 PK에 해당하는 값이 PK 값이나 NULL이어야 함
-속성 무결성:속성의 값은 기본값, NULL 여부, 지정된 도메인(데이터타입, 길이)규칙을 준수하여 존재해야 함
-사용자 무결성:사용자의 의미적 요구사항 준수


제약명
-엔티티 무결성:PK, 유니크키
-속성 무결성 : CHECK, NULL/NOT NULL, DEFAULT
-참조 무결성:FK
-사용자 정의 무결성:TRIGGER, USER DEFINE DATA TYPE

DBMS요소
-PK : 지정된 컬럼들이 유일성이 위배되는 일이 없음을 보장
NULL값이 될수 없음

-UI(유니크키): 다중의 보조키 개념을 지원함
지정된 컬럼들이 유일성이 위배되는 일이 없음을 지원함
NULL  허용

-FK:테이블간 논리적 관계가 유지됨을 보장함
FK값은 반드시 참조하는 테이블의 PK값으로 나타나야 함
FK값은 NULL 값을 가질수 있음
CASCADED OPTION:MASTER 삭제시 레코드가 함께 삭제됨
NULLFILELD OPTION:MASTER 삭제시 해당 값을 NULL로 세팅함
RESTRICTED OPTION:FK가 존재하면 MASTER 레코드를 삭제할 수 없음

-DATA TYPE
데이터형을 제한함으로써 데이터 무결성을 유지함

-CHECK CONSTRAINT
데이터를 추가할때마다 SQL 서버가 해당 값이 해당 컬럼들에 지정된 CHECK 제약을 위배하는지를 검사함으로써 데이터 무결성 유지

-DEFAULT
특정 컬럼에 대해 명시적으로 값을 입력하지 않은 경우에 SQL 서버가 자동적으로 지정된 값을 삽입할 수 있도록 함으로써 데이터 무결성 유지
INSERT또는 UPDATE에서 DEFAULT 키워드를 사용할 수 있음

-TRIGGER
테이블의 내용을 변경하려는 특정 사건(DB연산)에 대해서 DBMS가 미리 정의된 일련의 행동(DB 연산)들을 수행하는 매커니즘
DBMS서버에 의해 자동적으로 호출됨
데이터에 대한 변경을 시도할때마다 자동적으로 호출됨(데이터의 변경 전 상태와 변경후의  상태를 사용)
트랜젝션의 철회와 같은 동작을 수행할 수 있음
저장프로시저의 특별한 형태로서 SQL의 모든 기능을 이용할 수 있음
참조 무결성을 위해 사용할수도 있음, 참조 무결성이 위배되는 경우엔 원하는 동작을 하도록 트리거를 구성하면 됨


14. 트랜젝션 관리의 실무적용
트랜젝션이란
데이터 베이스에 행해지는 작업의 논리적인 단위이다

트랜젝션의 특징
트랜젝션이라고 불리기 위해서는 ACID라 불리는 4가지 속성을 가져야 한다
-ATOMICITY(원자성)
트랜젝션은 분해가 불가능한 최소의 단위로서 연산 전체가 처리되거나 전체가 처리되지 않아야 함 - COMMIT/ROLLBACK 연산
-CONSISTENCY(일관성)
트랜젝션이 실행을 성공적으로 완료하면 언제나 모순 없이 일관성 있는 데이터베이스 상태를 보존함
-ISOLOATION(고립성)
트랜젝션이 실행 중에 생성하는 연산의 중간 결과를 다른 트랜젝션이 접근할 수 없음
-DURABILITY(영속성)
성공이 완료된 트랜젝션의 결과는 영속적으로 데이터베이스에 저장됨

프로젝트를 할때 트랜젝션을 분석하는 가장 중요한 이유는 데이터에 대한 업무적인 무결성을 유지할 수 있도록 프로세스와 데이터 설계 사상에 반영하기 위해서이다
그 다음 이유는 데이터베이스에 발생되는 처리량을 분석하여 용량 산정의 근거 자료로 삼아 성능이나 자원을 배치할때 효율성을 높이기 위해서다


15. 정규화의 실무적용
데이터베이스에 정규화를 수행하지 않으면 도대체 무슨일이 발생하는 것일까?
-데이터를 입력할 때 불필요한 데이터와 같이 입력을 해야 한다
-데이터를 수정할때 한건의 데이터만 수정하고 싶어도 불필요하게 여러 건의 데이터를 수정해야 하는 경우가 생긴다
-데이터를 삭제하기 원할때 원하지 않는 데이터까지 삭제되려고 하기 때문에 정상적으로 데이터를 삭제하지 못하고 수정으로 삭제를 처리해야 하는 경우가 생긴다
-부가적으로 과다하게 중복된 데이터가 여러 테이블에 분산되어 있기 때문에 데이터 저장공간이 너무 커져 스토리지의 낭비가 나타난다

정규화 이론
-실세계에서 발생하는 데이터들은 수학적인 방법에 의해 구조화시켜 체계적으로 데이터를 관리할 수 있도록 하는 것

정규화 정의
-속성들 간의 종속성을 분석해서 기본적으로 하나의 종속성이 하나의 릴레이션으로 표현되도록 분해해 나가는 과정
-데이터 처리의 입력이상, 수정이상, 삭제이상을 제거하기 위해 데이터의 함수적 종속성이나 조인속성을 이용하여 분리, 통합하는 방법
-다양한 유형의 검사를 통해 데이터 모델을 더 구조화시키고 개선시켜나가는 절차에 관련된 이론

정규화의 기본원칙
-정보가 손실되지 않아야 하고 중복성이 감소되어야 하며 테이블이 분리되어야 한다는 것(5차 정규화의 경우에는 통합)

정보의 무손실:분해된 릴레이션이 표현하는 정보는 분해되기 전의 정보를 모두 포함하고 있어야 하며, 더 바람직한 구조여야 함
데이터 중복성 감소:중복으로 인한 이상 현상 제거
분리의 원칙: 하나의 독립된 관계성은 하나의 독립된 릴레이션으로 분리하여 표현해야 함


1차 정규화: 복수의 속성값을 갖는 속성을 분리함
2차 정규화:주식별자에 종속(DEPENDENCY)적이지 않은 속성을 분리함
부분 종속(DEPENDENCY) 속성을 분리함
3차 정규화 : 속성에 종속(DEPENDENCY)적인 속성을 분리함
이전 종속(DEPENDENCY) 속성을 분리함
보이스-코드 정규화 : 다수의 주식별자를 분리함
4차 정규화:다가(MULTI-VALUED) 종속(DEPENDENCY) 속성 분리
5차 정규화:결합 종속(DEPENDENCY)일 경우 두개 이상의 N개로 분리함


*위의 개념을 함수적 종속성에 근거하여 표현 하면 다음과 같이 표현됨
함수적 종속성
1)함수적 종속성(FUNCTIONAL DEPENDENCY)
-릴레이션의 한속성 X가 다른 속성 Y를 결정지을 때 Y는 X에게 함수적으로 종속됨. X->Y
-X는 결정자 Y는 종속

2)부분함수적 종속성(2NF)
-X->Y에서도 Y가 X의 부분 집합에 대해서도 함수적으로 종속되는 경우

3)이행함수적 종속성(3NF)
-릴레이션 R에서 속성A->X이고 X->Y이면 A->Y임

4)결정자 함수적 종속성(BCNF)
-함수적 종속이 되는 결정자가 후보키가 아닌 경우
-즉, X->Y에서 X가 후보키가 아님

다중값 종속성(MULTIVALUED DEPENDENCY, 4NF)
-한 관계에 둘 이상의 독립적 다중값 속성이 존재하는 경우
-X, Y, Z 세개의 속성을 가진 릴레이션 R에서, 속성쌍(X,Z) 값에 대응하는 Y값의 집합이 X값에만 종속되고 Z값에는 독립이면 Y는 X에 다중값 종속된다고 하고 X->Y로 표기함

조인종속성(JOIN DEPENDENCY, 5NF)
-둘로 나눌 때에는 원래의 관계로 회복할 수 없으나 셋 또는 그 이상으로 분리시킬 때에는 원래의 관계를 복원할 수 있는 특수한 경우임


정규화에 대해 자세히는
한빛미디어 데이터베이스 설계와 구축이라는 책을 참조

앱)아는만큼 보이는 데이터베이스 설계와 구축 요약

Posted by HULIA(휴리아)
2018. 2. 21. 10:52 백엔드개발/데이터베이스
1. PK컬럼순서 대충하지 말자

데이터베이스를 생성할때는 분석->설계->구축->테스트->이행 프로세스를 거치는데 설계 단계 이후 완성된 데이터 모델을 토대로, 물리적인 테이블을 정해진 DBMS에 맞게 생성하게 된다

이때 보통 상용화된 데이터 모델링 툴(ERWin, ERStudio, Rational Rose 등)을 이용해 모델을 만들고 DDL을 생성하기 때문에 설계 단계에서 데이터 베이스를 생성할때 PK 컬럼의 순서는 그다지 신경쓰지 않고 생성하게 되는 경우가 많이 있다

PK순서가 잘못되어 SQL의 성능이 저하되는 경우는 인덱스를 이용하지 못한 경우와 인덱스는 이용하는데 범위가 넓어져 성능이 저하 되는 경우임

테이블 생성전에 SQL Where 절을 분석하여 엔티티타입의 PK 컬럼 순서를 조정하는 작업을해야한다

테이블의 PK컬럼순서와 쿼리 순서를 맞춰야 한다

2. 식별자관계와 비식별자관계 설정 이것만은 알고 해야

식별자관계와 비식별자관계를 잘 모르고 데이터 모델링을 진행할때 발생 오류
-식별자관계만을 이용하여 데이터 모델링을 전개할 경우, PK속성의 숫자가 증가할수록 관련된 SQL구문이 복잡해져 복잡성으로 인한 개발 오류를 유발하게 된다
-비식별자관계만을 이용하여 데이터모델링을 전개할 경우 데이블간의 과다한 조인을 유발하여 조인에 의한 성능 저하를 불러오게 된다

비식별자관계를 선정하는 기준
관계분석 -> 관계의 강약분석 -> 자식테이블 독립 PK 필요 -> SQL 복잡도 증가 개발생산성 판단

관계의 약한관계시, 독립 PK 구성시, SQL  복잡도 증가 개발생산성 저하시에 PK 속성 단순화할때 비식별자관계 설정 고려함

식별자관계
목적:강한 연결관계 표현
자식PK영향:자식PK의 구성에 포함됨
표기법 :실선 표현
연결고려사항
-반드시 부모 엔티티타입 종속
-자식 PK 구성에 부모 PK 포함 필요
-상속받은 PK 속성을 타 엔티티타입에 이전 필요

비식별자관계
목적:약한연결관계 표현
자식PK영향:자식일반속성에포함됨
표기법:점선표현
연결고려사항
-약한 종속관계
-자식PK구성을 독립적으로 구성
-자식PK구성에 부모PK부분 불필요
-부모 쪽의 관계참여가 선택 관계임
-상속받은 PK속성을 타 엔티티타입에 재상속 차단 필요

3 이력유형 데이터 모델링 이렇게 하라

이력데이터모델의 특징
-시간에 따라 발생한다
-동일한 칼럼에 발생한다
-대량 데이터가 발생할 가능성이 높다
-성능에 영향을 주는 경우가 많다

내부 스냅샷 이력
특징:한개의 테이블
장점
-이력관계 설정 용이함
-데이터중복없음
고려할점
-현재 관계만 필요한 경우 불필요한 PK속성 상속
-대량의 데이터가 한군데 집중됨

1:M 스냅샷 전체 이력
특징:두개의 테이블(현재와 현재+과거 테이블)
장점
-현재/이력 관계 설정 용이함
-현재 데이터에 대한 성능 처리 용이함
고려할점
-현재 데이터 중복
-관리 항목 증가

1:M스냅샷 과거 이력
특징:두개의 테이블(현재와 과거 테이블)
장점
-현재/이력관계 설정 용이함
-현재 데이터에 대한 성능 처리 용이함
-현재 데이터 중복 없음
고려할 점
-관리 항목 증가
-현재와 과거 데이터 조회시 조인이 발생하여 성능 저하됨

1:M 스냅샷 군집 전체 이력
특징:N개의 테이블(현재와 현재+과거테이블)
장점
-칼럼이 많은 데이블 관심사 분리
-컬럼 분리로 DISK IO경감
-관심 항목 관계 설정 가능
고려할 점
-관리 항목 증가 큼
-과거 데이터 조회 시 조인 과다 발생으로 성능 저하
-현재 데이터 중복

1:M 스냅샷 군집 과거 이력
특징:N개의 테이블(현재와 과거 테이블)
장점
-컬럼이 많은 테이블 관심사 분리
-컬럼 분리로 DISK IO 경감
-관심 항목 관계 설정 가능
-현재 데이터 중복 없음
고려할 점
-관리 항목 증가 큼
-현재와 과거 데이터 조회시 조인이 과다 발생하여 성능 저하

이 중 가장 많이 사용되는 유형은 1:M 스냅샷 전체 이력형식이다


4. 엔티티통합? 분리?
적절한 기준에 따라 엔티티타입의 통합과 분리를 결정하는 것은 전문적인 모델링을 전개하는 사람에게 매우 필요한 기술이다

엔티티타입의 통합과 분리에 대한 기준을 어떻게 할것인가는 실전 프로젝트를 전개할때 중요한 고려요소가 된다

업무패턴을 먼저 이해하고 해당업무에서 날아오는 트랜잭션의 패턴을 분석한 다음 엔티티타입의 통합과 분리를 결정해야 한다

엔티티통합의 장점과 단점(6가지)
성능
효과:성능 좋아짐현상, 성능 나빠짐 현상 모두 존재
특징장점:정보가 한군데 집약되어 있으므로 조인 발생을 최소화하여 성능저하를 예상할 수 있음
특징단점:대량의 데이터가 한군데 존재할경우 트랜잭션의 집중현상과 데이터량증가로 인한 성능 저하가 나타날 수 있음
고려요소:정보의 양이 대용량이거나, 트랜잭션이 집약된 정보에 집중될 것으로 예상된다면 엔티티타입 분리가 바람직함

속성제약
효과:나빠짐
특징
-고유한 속성의 제약조건을 걸지 못하는 현상이 발생함
-Default, Check Constraint, Null등 고유한 컬럼 규칙을 지정하지 못하게 됨
고려요소:애플리케이션에서 모두 체크해야함

유연성
효과:나빠짐
특징
-분리되어 있을때 각각의 엔티티타입별로 다른 엔티티타입과 가질 수 있는 관계를 통합하면 관계가 모호해지거나 정확한 관계를 설정할 수 없게 되는 경우가 발생함
고려요소:논리적인 데이터 모델의 경우 유연성이 중요함

업무이해도
효과:나빠짐
특징
-고유한 관계의 해석이 안되므로 데이터 모델만을 보고 업무 파악에 어려움이 발생함
고려요소:논리와 물리 데이터 모델을 구분하여 생성할 수 있음

복잡도
효과:복잡도가 낮아짐
특징
-여기저기 비슷한 정보가 흩어져 있어 복잡해 보이는 데이터 모델을 단순하게 유도할 수 있음


유지보수성
효과:좋아짐
특징
-관리해야할 테이블 개수가 줄어들어 유지보수가 용이해짐





5. PK(primary key)와 UI(unique index)의 차이점

PK
목적:Constraint+Index
공통점:유일성보장
참조무결성:PK/FK에 의해 지정가능
테이블 당 개수 :1개만 가능
인덱스 생성:unique index 생성
역공학 적용시 : PK 인식 가능
NULL 허용:허용 안됨

UI
목적:INDEX
공통점:유일성 보장
참조 무결성:지정 불가능
테이블당 개수:여러개 가능
인덱스 생성:UNIQUE INDEX 생성
역공학 적용시:PK인식 불가능
NULL 허용 : 허용됨

UI만을 이용하였을때 장단점
장점
-PK/FK가 존재하지 않아 DBA가 데이터베이스를 관리하기 쉽다
-개발시점에 데이터 제약이 없으므로 개발이 용이하다
-PK/FK를 이용하지 않기 때문에 성능이 좋아질 수도 있다

단점
-데이터 무결성이 깨어질 수 있다
-데이터무결성이 깨지므로 데이터전환작업시 데이터 정리 작업이 필요하다
-데이터 모델과 테이블의 관계가 일치하지 않는다
-UI는 한 테이블에 여러개 만들수 있으므로 테이블만을 보고는 PK가 무엇인지 구분할수 없다

데이터 모델링할때 그리고 데이터베이스를 구축할때 다음의 네가지 기준에 의하 판단을 해야 한다
-데이터 무결성
-데이터베이스 서능
-데이터베이스 관리의 용이성
-개발자 편의성

6. 자기참조관계 모델링 기법


7. 엔티티 타입 도출
명사를 이용해서 엔티티 타입 도출
데이터 모델과 프로세스 모델 그리고 상관 모델링을 함께 진행하면서 검증수행함

과감하게 업무기술서를 읽어보고
정확하게 업무를 분석하고
해당 업무에서 지속적으로 사용하는 장표를 모으고
해당 업무에 대해 전문가라고 할 수 있는 고객을 만나 어떤 정보를 관리해야 하는지 인터뷰해서 알아내는 사람이 진정한 데이터 모델링의 전문가

엔티티 타입 도출방법은 세가지
-명사형 도출(초기 엔티티타입을 도출할때 가장 많이 사용하는 방법중에 하나)
-정규화 이용(1차, 2차, 3차, BCNF, 4차, 5차)
-엔티티 타입 구분에 의한 4STEP 데이터 모델링(구조 -> 업무흐름 -> 기술적 모델링 -> 모델 검토의 단계)

8. 데이터 모델링 관계의 중요성
관계를 표현하지 않으면 다음과 같은 문제가 생김
-업무의 구조와 흐름을 파악할 수 없다
-PK의 구조를 정확하게 가져갈 수 없다
-효율적인 SQL구문을 작성할 수 없다
-참조 무결성 제약 조건에 의한데이터 참조 무결성 유지가 어렵다

모든 엔티티타입은 관계를 가져야 한다
단 예외적인 케이스 3가지 경우
-코드성 엔티티타입을 표현
-통계성 엔티티타입을 표현
-다른 시스템의 엔티티타입을 참조하거나 참조되는 경우

9. 용어사전과 도메인을 정의하라
데이터 모델링을 하면서 용어사전과 도메인을 정의하지 않고 모델링을 진행할 경우 다음과 같은 문제가 나타난다
-일관성있고 품질이 좋은 데이터 모델/데이터베이스를 구축할 수 없다(데이터타입과 길이가 똑같지 않음)
-애플리케이션 로직 에러를 초래할수 있다(데이터 타입과 길이가 똑같지 않음,  INDEX를 타지 않음)
-데이터 처리에 성능 저하를 유발할 수 있다(PK의 데이터 타입과 길이가 똑같지 않음)

10. 데이터 모델을 검증하라
Validation = 고객 요구사항에 대해 구축된 소프트웨어가 조건을 만족하였는지 체크
Verification = 기본적인 시스템의 요건을 만족하였는지 확인

업무에서 최종적인 데이터베이스를 구축할때까지 데이터 모델의 관점에서는 2개의 큰 마일스톤이 있다
첫번째, 논리적 관점의 데이터 모델의 완성된 형태
두번째, 데이터베이스특성을 고려하여 성능과 용량을 고려한 물리적 관점의 데이터 모델의 형태라 할 수 있다

데이터 모델을 체크할때는 엔티티타입, 속성, 관계, PK, 용어/도메인 정의로 구분한 체크리스트를 가지고 검증하게 된다

엔티티 타입 검토 체크리스트
-선정된 PK가 업무적으로 발생하는 자료의 유일성을 보장?
-자료의 발생 유형이 유사한 엔티티는 통합되었는가?
-PK의 순서는 시스템의 성능을 고려하여 적잘한 순서로 정의되어 있는가?

속성검토 체크리스트
-동일 명칭을 가지는 속성의 타입과 크기는 동일한가?
-감사, 통계등을 고려하여 속성이 정의되어있는가?
관계검토 체크리스트
-엔티티타입 간의 관계까 M:N인 속성은 없는가?
-엔티티타입 간의 관계는 업무적 흐름과 규약이 일치하는가?

도메인/용어 체크리스트
-도메인의 변경에 따라 속성이 변경되고 있는가?
-데이터 모델의 용어가 일관성을 유지하고 있는가?

11. 논리/물리 데이터 모델을 생성하라
논리적인 데이터 모델 - 비즈니스 관점(업무중심의 모델링) - 인식부족 문제 발생가능성 있음
물리적인 데이터 모델 - 데이터베이스 오브젝트 관점(DB중심의 모델링) - knowhow 부족 문제 발생가능성 있음

논리적인 데이터 모델은 비지니스 형상화하여 노테이션을 이용한 모델로 표현하는 것이 가장 중요한 목적
물리적인 데이터 모델은 데이터베이스에 생성하기 위해 인덱스를 생성하며 성능을 향상시키기 위해 반정규화나 언티티타입의 통합과 분리 등을 하는 것이 주요한 목적

앱)Springframework version 버젼별 간단 특징 요약 역사

Posted by HULIA(휴리아)
2018. 2. 6. 13:46 백엔드개발/자바스프링
Springframework는 2004년에 처음 release되었음

2.0
XML namespace와 AspectJ support

2.5
annotaion 기반의 설정 방법 추가

3.0
Java5 지원
Spring Expression 지원
Java based bean metadata 지원
Type conversion and fileld formatting 지원
REST 지원
@MVC 추가
Java6 지원
Embedded 데이터베이스 지원

4.0
Java8 지원
WebSocket. SockJS, STOMP messaging 지원
Groovy Bean DSL 지원

앱)Slf4j API print format 정리 예제

Posted by HULIA(휴리아)
2018. 1. 31. 10:19 백엔드개발/자바스프링
debug, info, warn, fatal, error 모두 같은 형식을 지원하므로
 debug만 대표적으로 알아봄

slf4j.debug 메소드의 overloading 메소드 정리
debug(String arg0);
debug(Marker arg0, String arg1);
debug(String arg0, Object arg1);
debug(String arg0, Object...arg1);
debug(String arg0, Throwable arg1);
debug(Marker arg0, String arg1, Object arg2);
debug(Marker arg0, String arg1, Object...arg2);
debug(Marker arg0, String arg1, Throwable arg2);
debug(String arg0, Ojbect arg1, Obejct arg2);
debug(Marker arg0, String arg1, Object arg2, Object arg3);



Marker
Marker fatal = MarkerFactory.getMarker("FATAL");

Logger
Logger logger = LoggerFactory.getLogger("LOG");

Throwable과 Exception은 비슷
try-catch문에서 catch문에서 Exception출력을 할때 이용하거나 Exception을 throw 할때 사용


예시1)
logger.error(fatal, "Failed to obtain JDBC connection", e);

예시2)
logger.debug("Entry number: " + i + "is" + String.valueOf(entry[i]));

예시3)
Object entry = new SomeObject();//자바의 모든 객체 다 쓸 수 있음
logger.debug("The entry is {}" , entry);
//출력 : The entry is 3

예시4)
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
//출력 : The new entry is 3. It replaces 6.

예시5)
logger.debug("Value {} was inserted between {} and {}.", newVal, below, above);
//출력: Value 7 was inserted between 5 and 10.


예시6)
logger.debug("Set {1,2} differs from {{}}", "3");
//출력 : Set {1,2} differs from {3}


예시7)
logger.debug("Set \\{} differs from {}", "3");
//출력 : Set {} differs from 3


예시8)
logger.debug("File name is c:\\\\{}.", "file.zip");
//출력 : File name is c:\file.zip.


예시9)
String s = "hello world";
try {
Integer i = Integer.valueOf(s);
}catch(NumberFormatException e) {
 logger.error("Failed to format {}, s, e);
}


예시10)
public class LoggerUtil {
public static void debug (Logger logger,String msg,Object...params){
if (logger.isDebugEnabled ()){
logger.debug (msg,params);
}
}
}

앱)springframework annotation 예제

Posted by HULIA(휴리아)
2018. 1. 25. 16:18 백엔드개발/자바스프링
@transactional(rollbackFor={Exception.class})

@component

@service

@repository("DAO")

@Resource(name="sqlSessionTemplte")

@Autowired

앱)메이븐 maven pom.xml 예제

Posted by HULIA(휴리아)
2018. 1. 25. 16:10 백엔드개발/자바스프링
<project xmlns:"http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>Batch</groupId>
  <artifactId>Batch</artifactId>
  <version>1.0.0</version>

   <properties>
     <lib.dir>lib</lib.dir>
     <conf.dir>conf</conf.dir>
     <jar.name>JobManager</jar.name>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ch.qos.logback-version>1.1.7</ch.qos.logback.version>
<org.slf4j-version>1.7.21</org.slf4j-version>
<powermock.version>1.7.0</powermock.version>
<mockito.version>1.10.17</mockito.version>
<junit.version>4.12</junit.version>
<org.springframework-version>3.2.17.RELEASE</org.springframework-version>

<!-- slf4j와 logback과 상충된다-->
<org.logback-extensions-version>0.1.4</org.logback-extensions-version>
</properties>

<dependencies>
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.2.6.RELEASE</version>
       <exclusions>
           <exclusion>
               <groupdId>commons-logging</groupId>
               <artifactId>commons-logging</artifactId>
             </exclusion>
       </exclusions>

   </dependency>
   
   <dependency>
       <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.2.6.RELEASE</version>
</dependency>

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>4.2.6.RELEASE</version>
</depenency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.1.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-commons<artifactId>
<version>1.11.4.RELEASE</version>
</dependecy>

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.42</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.1.0</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>

<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${ch.qos.logback-version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${ch.qos.logback-version}</version>
</dependency>


<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</test>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
</dependency>

<!--logback 4개 대신에 요거 하나를 써도 된다 springframework에서는 -->
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>${org.logback-extensions-version}</version>
</dependency>

<dependency>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
</dependency>

<dependency>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
</dependency>




</dependencies>


<build>
  <plugins>     
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-comiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
       <source>1.7</source>
       <target>1.7</target>
       <encoding>UTF-8</encoding>
      </configuration>
    </plugin>


<plugin>
     <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-resources-plugin</artifactId>
      <version>2.4</version>
      <executions>
          <execution>
             <id>copy-resources-conf<id>
             <phase>prepare-package</phase>
             <goals><goal>copy-resources</goal></goals>
             <configuration>
                      <outputDirectory>${project.build.directory}/conf</outputDirectory>
        <resources><resource>
               <directory>src/main/resources</directory>
           </resource></resources>
         </configuration>
    </execution>
    <execution>
       <id>copy-resources-bin</id>
       <phase>prepare-package</phase>
        <goals><goal>copy-resources</goal></goals>
        <configuration>
             <outputDirectory>${project.build.directory}/bin</outputDirectory>
    <resources><resource>
             <directory>src/main/bin</directory>
       </resource></resources>
      </configuration>
      </execution>
     </executions>
   </plugin>


<plugin>
     <groupId>org.codehaus.mojo</groupId>
      <artifactId>build-helper-maven-plugin</artifactId>
      <version>1.11</version>
      <executions>
         <execution>
                 <id>timestamp-property</id>
                 <phase>validate</phase>
                <goals><goal>timestamp-property</goal></goals>
               <configuration>
                     <name>current.time</name>
                     <pattern>yyyyMMddHHmmss</pattern>
                 <locale>ko_KR</locale>
                 <timeZone>Asia/Seoul</timeZone>
             </configuration>
          </execution>
        </executions>
</plugin>




<plugin>
     <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <version>2.4</version>
      <configuration>
            <finalName>JobManager</finalName>
            <excludes>
                  <exclude>**/*.properties</exclude>
 <exclude>**/logback*.xml</exclude>
 <exclude>**/spring/**</exclude>
 <exclude>**/mybatis/**</exclude> 
</excludes>
<archive>
   <manifest>
        <addDefaultImplmentationEntries>true</addDefaultImplementationEntries>
<mainClass>com.test.jobmanager.JobManager</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>${lib.dir}/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>${conf.dir}/</Class-Path>
<Revision>${build.number}</Revision>
<Build-Date>${current.time}</Build-Date>
</manifestEntries>
</archive>
</configuration>
</plugin>




<plugin>
     <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
          <execution>
              <id>copy-dependencies</id>
              <phase>package</phase>
              <goals><goal>copy-dependencies</goal></goals>
            </execution>
         </executions>
         <configuraion>
               <outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
</configuraion>
</plugin>




<plugin>
     <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-assembly-plugin</artifactId>
      <version>2.4</version>
      <configuration>
          <descriptors><descriptor>src/main/assemblies/package.xml
          </descriptor></descriptors>
         <finalName>${project.artifactId}-${current.time}</finalName>
 <appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
   <execution>
      <id>tarball</id>
       <phase>package</phase>
       <goals><goal>single</goal><goals>
    </execution>
</executions>
</plugin>





<plugin>
     <groupId>org.codehaus.mojo</groupId>
      <artifactId>build.helper-maven-plugin</artifactId>
      <version>1.11</version>
      <executions>
          <execution>
              <id>timestamp-property</id>
              <phase>validate</phase>
              <goals><goal>timestamp-property</goal></goals>
          <configuraion>
              <name>current.time</name>
              <pattern>yyyyMMddHHmmss</pattern>
               <locale>ko_KR</locale>
               <timeZone>Asia/Seoul</timeZone>
          </configuraion>
          </execution>
       </executions>
</plugin>





<plugin>
     <groupId></groupId>
      <artifactId></artifactId>
      <version></version>






</plugin>




  </plugins>
  <pluginManagement>
      <plugins>
            <!-- This plugin's configuraion is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
       <plugin>
           <groupId>org.eclipse.m2e</groupId>
          <artifactId>lifecycle-mapping</artifactId>
          <version>1.0.0</version>
          <configuration>
              <lifecycleMappingMetadata>
                  <pluginExecutions>
                      <pluginExecution>
                         <pluginExecutionFilter>
    <groupId>org.codehaus.mojo</groupId>
     <artifactId>build-helper-maven-plugin</artifactId>
      <versionRange>[1.11,)</versionRange>
       <goals><goal>timestamp-property</goal></goals>
  </pluginExecutionFilter>
<action><ignore /></action>
                     </pluginExecution>
                   </pluginExecutions>
</lifecycleMappingMetadata>
          </configuraion>
        </plugin>
       </plugins>
  </pluginManagement>
 

</build>
</project>

앱)custom Exception class 클래스 예제

Posted by HULIA(휴리아)
2018. 1. 25. 14:56 백엔드개발/자바스프링
public class testException extends Exception {
    private static final long serialVersionUID = 7897401638242416328L;

public testException(String msg){
    super(msg);
}

}

앱)springframework로 batch 예제(main+applicationcontext+properties+logback)

Posted by HULIA(휴리아)
2018. 1. 23. 10:12 백엔드개발/자바스프링
☆☆☆☆☆main
public class mainApplicaion{
    public static void main(String[] args) {
       String jobMgr = System.getProperty("jobmgr.home");
       if(StringUtils.isEmpty(jobMgr)){
       //에러(jobMgr Home is Empty)
       return;
      }
      if( !(new File(jobMgr)).exists()) {
     //에러(Invalid jobmgr Home + jobMgr+)
      return;
      }
   
      String serverType = System.getProperty("server.type");
      if(StringUtils.isEmpty(serverType)){
      //에러
      return;
     }
     
      LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
      JoranConfigurator jc = new JoranConfigurator();
       jc.setContext(context);
       context.reset ();//우리가 설정한 logback 설정만 적용된다
       try{
          jc.doConfigure(new ClassPathResource("logback"+System.getProperty("server.type")+".xml").getInputStream());
       }catch(Exception e){
          return;
       }



      ApplicationContext springContext = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
  }
}


☆☆☆☆☆scheduler@service
@scheduled(fixedDelayString="jobmgr.runnig.interval"+"000")
public void doTest(){
     doTestBiz();
}



☆☆☆☆☆service, biz @service
@Value("${jobmgr.running.interval}")
private String interval;

@Async("testExcecutor")
public doTestBiz(){

}


☆☆☆☆☆application context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/core http://activemq.apache.org/schema/core/activemq-core.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">

<context:anntaion-config />

<context:component-scan base-package="com.istoryful.test" />

<task:anntation-driven />

<task:schduler id="scheduler" pool-size="${jobmgr.defaultSchedulerSize}" />

<task:executor id="testExecutor" pool-size="${jobmgr.testExecutor.size}" />

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property anme"locations">
          <list>
                <value>batch${server.type}.properties</value>
          </list>
     </property>
</bean>

<bean id="dataSource" class="com.istoryful.util.CrytoDataSourceUtil" destory-method="close">
    <property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxTotal" value="${jdbc.maxTotal}" />
<property name="maxIdle" value="${jdbc.maxIdle}" />
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
   <property name="dataSource" ref="dataSource" />
   <property name="configLocation" value="classpath:mybatis/mybatisConfig.xml" />
</bean>

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="sqlSessionFactory" />
</bean>

<bean class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="dataSource" />
</bean>

<tx:annotation-driven trasction-manager="transactionManager" />

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource" />
</bean>





☆☆☆☆☆properties
jdbc.vendor=mysql
jdbc.driver=
jdbc.url=
jdbc.username=
jdbc.password=
jdbc.maxTotal=
jdbc.maxIdle=

jobmgr.defaultSchedulerSize=1
jobmgr.testExecuotr.size=3

jobmgr.running.interval=60

☆☆☆☆☆vm arguments
-Djobmgr.home=C:\Batch
-Dserver.type=Local


☆☆☆☆☆logback
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="1 seconds">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
   <encoder>
       <pattern>%-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{0} - %msg %n %ex</pattern>
</encoder>
</appender>


<appender name="INFOFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
       <fileNamePattern>${jobmgr.home}/logs/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
    <pattern>%-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{0} - %msg %n %ex</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <onMatch>DENY</onMatch>
    <onMismatch>ACCEPT</onMismatch>
</filter>
</appender>


<appender name="ERRORFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${jobmgr.home}/logs/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
    <pattern>%-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{0} - %msg %n %ex</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch><DENY</onMismatch>
</filter>
</appender>

<logger name="org.apache" level="INFO" />
<logger name="org.springframework" level="INFO" />
<logger name="com.amazonaws" level="INFO" />

<logger name="JOB" level="INFO">
   <appender-ref ref="INFOFILE" />
   <appender-ref ref="ERRORFILE" />
</logger>

</configuration>



☆☆☆☆☆logger
private static final Logger logger = LoggerFactory.getLogger("JOB");


☆☆☆☆☆mybatisconfig
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <settings>
     <setting name="cacheEnabled" value="false" />
      <setting name="useGeneratedKeys" value="true" />
     <setting name="defaultExecutorType" value="REUSE" />
     <setting name="defaultStatementTimeout" value="3480" /><!-- SQL timeout 58 minutes-->
</settings>
    
   <typeAliases>
     <typeAlias alias="VO" type="com.istoryful.VO />
   </typeAliases>

<mappers>
   <mapper resource="mybatis/mysql/DAO.xml" />
</mappers>

</configuration>


☆☆☆☆☆sql
<?xml version="1.0" encoding="UTF-8"?>

<mapper namespace="sql.DAO">


   <resultMap id="Vo" type="VO">
       <result property="test"  column="TEST" />
       <result property="test"  column="TEST" />
       <result property="test"  column="TEST" />
       <result property="test"  column="TEST" />
</resultMap>



<insert id="testInsert">
</insert>


<select id="testSelect">
</select>

<update id="testUpdate">
</update>

</mapper>

앱)자바 외부 실행파일 실행 1.7 이상에서 processbuilder 예제로 실행하고 정상적으로 종료

Posted by HULIA(휴리아)
2018. 1. 22. 10:36 백엔드개발/자바스프링
String[] cmd = new String[] {"copy","a.txt","b.txr"};
ProcessBuilder builder = new ProcessBuilder (cmd);
//builder.redirectOuptput (Redirect.INHERIT);
//builder.redirectError (Redirect.INHERIT);
Process process;

process = builder.start ();

BufferedReader stdOut = new BufferedReader( new InputStreamReader (process.getInputStream ()) );

while( (str = stdOut.readLine ()) != null ) {
sysout (str);

//실행중에 에러가 났을때
if (str.contains ("ERROR:")){
throw new Exception (str);
}
//실행파일이 정상적인 위치에 없을때
else if(str.contains("No such file or directory"){

}
else{
logger.info (str);
}
}

//프로세스 정상종료(파일사이즈 정상적으로 업데이트 완료)
process.waitFor ();

앱)runable jar 파일 실행이 되지 않을때 classnotfoundexception에러 날때

Posted by HULIA(휴리아)
2018. 1. 15. 15:14 백엔드개발/자바스프링
jar 파일의 META-INF의 아래에 있는 MANIFEST.IMF에 설정이 잘 되어있는지 확인

Clas-Path
Main-Class
반드시 확인

jar파일 실행시킬때 자바옵션에 설정되어있어도 jar파일 내부의 manifest파일을 참조하니 빌드할때 꼭 확인하기