스프링 프레임워크의 주요 철학 중 하나로 가장 큰 테두리 중 하나는 DI(Dependency Injection) 이다.


Dependency Injection 에 대해 먼저 살펴보자면, 말그대로 "의존성 주입" 을 말하며, 스프링 프레임워크는 Framework 레벨에서 DI 를 제공해준다.


Spring 의 Container 들은 Bean 객체들을 관리하는 데 있어서 DI 를 이용하며 이를 통해 Life Cycle 을 용이하게 관리할 수 있으며 이 것이 스프링 프레임워크의 핵심적인 동작이라고 할 수 있다.


즉, 프레임워크 레벨의 관리를 통해 개발자는 객체들간의 의존성에 신경을 덜 쓰고 Coupling 을 줄일 수 있으며 높은 재사용성과 가독성있는 코드를 만들어낼 수 있다.


이를 제어의 역전(Inversion Of Control) 이라 하며, 이것이 스프링 프레임워크의 특징적인 개념인 IOC 이다.

(클래스 관리의 주체가 개발자가 아닌 프레임워크라는 뜻이다.)


그리고 결과적으로 이러한 개발 편리성은 높은 생산성을 이끌어낼 수 있는 스프링의 큰 장점이다.


- Dependency Injection 을 통해 얻을 수 있는 장점 -


 (1) Dependency Reduction : 객체 상호 간 의존성 관계를 줄여준다.


 (2) Reusable Structure : 코드의 재사용과 조합이 용이하다.


 (3) Readability : 코드들이 분리되다보니 가독성이 뛰어나진다.


 (4) Loose Coupling & Easy to change : 구조는 변화에 민감하지 않을 수 있다.


그 외에 테스트가 용이하고 다양한 패턴을 적용하는 데 유연하다는 점도 큰 장점이 될 수 있다.



Spring Framework 에서 개발자가 Dependency Injection 을 하는 데 몇가지 방법들이 있다.


 (1) Field Injection


 가장 흔히 볼 수 있는 Injection 방법으로 사용하기도 간편하고 코드도 읽기 쉽다.



public class Sample {
    
    @Autowired
    private Example example;
    
}


 많이 사용됨에도 불구하고 Field Injection 을 통한 의존성 주입은 권장되지 않는다.

 이유는 너무 추상적인 Injection 기법 때문이다. 의존성 주입이 쉽기 때문에 Dependency 관계가 복잡해질 우려가 있으며 이는 Framework 의 사용에 있어 다음과 같은 안티패턴적 측면을 갖는다.


 - Single Responsibility Principle Violation 

 : 너무나 쉬운 의존성의 주입은 하나의 클래스가 지나치게 많은 기능을 하게됨으로써 초기 설계의 목적성이자 "객체는 그에 맞는 동작만을 한다." 는 원칙에 위배되기 쉽다.

 위배된 경우 리팩토링의 비용은 크다.


 - Dependency Hiding

 : 추상화된 의존관계는 의존성을 검증하기 힘들게 만든다. 


 - DI Container Coupling

 : Field Injection 을 사용하면 해당 클래스를 곧바로 Instant 화시킬 수 없다. 이 부분 때문에 Constructor Injection 이 권장되는 이유이기도 하다.

 가령 Container 밖의 환경에서 해당 클래스의 객체를 참조할 때, Dependency 를 정의해두는 Reflection 을 사용하는 방법 외에는 참조할 수 있는 방법이 없다.

 DI Framework 는 Field Injection 된 클래스의 Instance 화에 대해서 Null Pointer Exception 을 만들어낼 것이다.


 - Immutability

 : Field Injection 된 객체는 final 을 선언할 수 없으므로 가변적(Mutable)이다. 객체는 변경될 수 있으며 이에 대한 대응에는 큰 비용이 든다.



 (2) Setter Injection


 선택적인 의존성을 주입할 경우 유용하며, Spring 3.x 대까지 가장 권장되던 방식이다.



public class Sample {
private Example example;

@Autowired
public void setExample(Example example) {
this.example = example;
}
}


 Field Injection 으로 인한 패턴적 위험성을 상당 부분 해소한다. Optional Injection 의 경우 권장되는 방식이다.

 @Required 어노테이션을 이용하면 의존성이 필요한 Setter 를 만들 수 있다.


 (3) Constructor Injection


 Spring 4.x 이상부터 권장되는 방식이다.



public class Sample {
    private final Example example;

    @Autowired
    public Sample(Example example) {
        this.example = example;
    }
}


 코드를 통해 알 수 있듯, final 선언이 가능하며 Immutability 에 대한 해소가 가능하며 의존성의 순환 참조(Circular Dependency) 에 대한 예방이 가능하다.

 순환 참조 시 위의 방법을 이용한 코드는 BeanCurrentlyCreationExeption 을 발생시킨다.

 역시 위에서 언급된 Container Coupling 문제도 해결이 되는데, 생성자를 통한 Injection 이므로 즉각적인 Instance 화 등에 대한 문제도 해결된다.



 많은 예제 코드들이 Field Injection 방식을 사용하고 있으나 Constructor Injection 의 사용이 권장된다.

추가로 참조한 바에 의하면 Spring Team 에서는 Setter 방식을 좀 더 권장하며 이유는 생성자가 지나치게 복잡해질 수 있기 때문이라고 한다.

패턴적 관점에서 이견이 있는 듯 하다.



Spring 4.3 이상부터는 생성자가 하나인 경우 @Autowired 를 사용하지 않아도 무방하다.



정리에 있어 다음 링크들을 참조하였다.


https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/


https://dzone.com/articles/dependency-injection-pitfalls


https://blog.outsider.ne.kr/753




LinkedHashMap 은 Linked List 의 특성을 지니는 HashMap 이다.


정확히는 HashMap 구현에 있어 Linked List 를 이용함으로써 키들 간의 순서를 보장해주고, Link 를 연결시켜 준다.


각 노드들은 before, after, next 상태를 저장하는 포인터를 지니고 있는데 각 포인터들은 다음을 가리킨다.


before : 해당 노드가 가진 키 값의 이전 키값을 참조한다. 이 노드 직전에 삽입된 노드를 가리킨다.


after : 해당 노드가 가진 키 값의 다음 키값을 참조한다. 이 노드 직후에 삽입된 노드를 가리킨다.


next : 해당 노드가 가진 키 값 내에서 다음 항목을 참조한다.


각 노드들은 상호 계층적으로 서로를 참조하며 HashMap 과 동일한 연산을 수행하는데 이 때,


put / remove 등 구조를 변경시키는 연산에 대해서 참조 링크를 바꾸어 가면서 기준값을 중심으로 정렬된 Linked List 형태를 유지한다.



좀 더 자세한 구현과 좋은 설명은 다음 링크를 참조하자.


https://medium.com/@mr.anmolsehgal/java-linkedhashmap-internal-implementation-44e2e2893036




메서드와 함수의 차이점은 간단하면서도 기초적인 내용이지만 자주 되새겨지는 개념이 아닌데다가, 비슷하게 혼용되어 사용되다보니 많이 잊게 되는 내용이다.


차이점 먼저 서술을 하자면, Method 는 "객체" 에 대한 코드를 말하고 동작(Operation)의 결과로 동작을 수행한 객체가 영향을 주거나 받는다.


즉, Operation 은 해당 메서드를 소유한 객체 중심으로 발생한다.


반면, Function 은 특정 형태의 Data 를 받아서 내부 동작(Operation)을 수행한 후 특정 형태의 Output Data 를 반환한다.


즉, Operation 은 객체와 무관한 독립적인 그 자체의 코드 조각으로의 의미를 지닌다.



- 정리


: Method - Member. 객체에 대한 Operation 을 수행하는 코드 조각.


: Function - Free. 객체와 독립적인 Operation 을 수행하는 코드 조각.



C 에서 사용되는 Logic 들은 모두 함수(Function) 이며 Java 에서 사용되는 Logic 들은 모두 메서드(Method) 이다.







캐시란 데이터를 임시로 저장해두는 장소를 말한다. 임시로 저장하여 사용하는 데이터의 종류는 제한이 없기 때문에 작게는 메모리에서 크게는 Logic 혹은 그 이상을 저장할 수 있다.


Cache 의 목적은 로직을 처리하는 데 있어서 빠른 접근성을 제공하는 것이며, 단순히 수동적으로 보관하는 것에 그치지 않고 이를 응용해서 작업의 결과를 저장함으로써 해당 로직의 불필요한 수행을 줄여주는 능동적인 역할까지 수행한다.


캐시가 될 수 있는 것은 일반적으로 로컬 메모리부터 별도의 디스크 볼륨까지 다양하지만 Cache 로 사용하기 위한 가장 중요한 요건은 데이터로의 접근성이다.


Cache 에 대한 접근성은 어떤 경우에도 로직 상에서 원하는 데이터에 직접 접근하거나 만들어내는 비용보다 저렴해야 한다. 그래야만 캐시로서의 의의가 있는 것이다.


그렇기 때문에 Cache 는 접근성이 빠른 공간(Space)에 빠른 자료구조를 사용한다.


캐시서버로 이용되는 서버들은 I/O 에 최적화된 공간이 사용되며 당연히 이에 대한 접근성에 있어서 효율적인 REST 등의 방법을 사용한다. 


컴퓨터 내에서 사용되는 캐시는 RAM보다 빠른 L1,L2 레지스터를 캐시로 사용하고, 프로그램 내에서 구현된 Software Cache 라면 접근에 용이한 Map 과 같은 자료구조에 인메모리(Inmemory)로 저장한다.


다음은 캐시를 이해하는 데 중요한 용어들이다.


 - origin : origin 혹은 origin server 는 캐시에 저장할 실 데이터가 존재하는 공간이다. 웹 캐시라면 DB 서버일 수도 있고, SW 내에서라면 파일 혹은 실행 함수 그 자체일 수도 있다.


 - cache expire : 프로세스 내에서 사용하는 인메모리 캐시나 영구히 상주해야하는 정보를 가진 캐시가 아니라면 Cache 는 Expire Date 를 갖고 있으며 해당 시간이 지나면 상한(Stale) 상태가 된다.


 - cache freshness : 캐시가 만료되지 않은 경우를 fresh 한 캐시라 하고 만료된 경우 stale cache 라 한다.


 - cache hit : 참조하려는 데이터가 캐시에 존재할 때 해당 캐시를 조회하는 걸 Cache hit 이라 한다.


 - cache miss : 참조하려는 데이터가 캐시에 존재 하지 않는 경우


 - cache hit ratio : 적중률로 전체 참조 횟수 대비 Cache hit 된 비율을 의미한다. 실질적으로 캐시의 설계는 Cache hit Ratio 를 높이는 데 초점을 둔다.



다음은 캐시의 동작에 대한 정책들이다.


 Cache Read : 


 - Cache-aside 방식 : 데이터를 참조 하기 전에 참조하고자 하는 값이 캐시에 존재하는지 확인한다. 여기서 값을 직접 비교하기 보다는 키를 이용해서 캐시에 접근한다. 

 Cache에 존재한다면 Cache에서 데이터를 가져온다. 만약 Cache에 존재하지 않는다면 origin에서 데이터를 가져오고 이를 캐시에 저장한다.


 - RT/WT/Write back 방식 : 캐시를 Main Data Source 로 사용하기 때문에 캐시에서만 데이터를 조회한다.

 RT/WT 방식(Read Through / Write Through) 은 Read Scalability 가 가장 뛰어나다.



 Cache Write :


 - Cache-aside 방식 : 캐시를 Application Level 에서 직접 갱신시켜준다. 개발자가 Flow 를 이해하고 Update / Evict 시켜줘야 하며, 그렇지 않으면 Cache 데이터와 DB 데이터가 불일치하는 Stale 현상이 발생한다.


 - Read Through / Write Through 방식 : 데이터의 쓰기시 캐시와 실제 저장공간의 데이터 둘다 최신화 시키는 작업이다. 

 캐시를 메인 Database 로 사용하는게 특징적이며, 캐시에 데이터를 먼저 업데이트하고 캐시에서 Main Database 를 즉시 갱신시킨다.

 양쪽의 데이터를 동일하게 유지할 수 있지만, 쓰기 시에 추가 부하가 생긴다는 단점이 있다.


 - Write Back 방식 : 데이터의 쓰기시 캐시의 데이터만 최신화 하고 해당 Cache 를 Evict 시켜놓는다. 이 후 RT/WT 방식처럼 캐시 값을 마킹된 기준으로 origin 으로 직접 반영(Write) 하는데, 캐시가 별도의 큐를 이용해서 Database Source를 비동기로 Update 시켜준다.

 Write Performance 와 DB Scalability 에 있어서 가장 뛰어나다.

 쓰기 작업이 Cache 에서만 발생하지만, Cache 가 만료되는 시점까지 Origin 에 Write Failure 가 발생한다면 데이터를 영구 손실할 위험이 존재한다. 



 Cache Replacement


  웹 캐시의 경우 자동 expire 하거나 명시적으로 cache 를 지워주는 동작을 해주지만, 캐시를 Scheduling 에 사용하는 컴퓨터나 알고리즘의 경우 Replicement Policy 를 갖는다.



 다음은 몇가지 대표적인 알고리즘들이다.


  - FIFO(First In First Out) : 오래된 캐시를 먼저 비우고 새로운 캐시를 추가하는 방식이다.


  - LIFO(Last In First Out) : 가장 최근에 반영된 캐시가 먼저 지워진다.


  - LRU(Least Recently Used) : 가장 최근에 사용되지 않는 순서대로 캐시를 교체한다. 가장 오랫동안 사용되지 않은 캐시가 삭제되며 일반적으로 사용되는 방식이다.


  - MRU(Most Recently Used) : 가장 최근에 많이 사용되는 순서대로 캐시를 교체한다. 휘발성 메모리를 이용해야 하는 특수한 상황에 사용된다.


  - Random : 말그대로 랜덤으로 캐시를 교체한다.


 운영체제를 배웠다면 페이지 교체 알고리즘이 Cache Replacement 정책을 사용한다는 것을 알 수 있을 것이다.



본 포스팅에서는 넓은 범위의 Cache 의 정의와 목적, 정책들에 대해 정리해보았다.


이론적인 부분이고 웹 캐시와는 조금 다르기도 하지만 중요한 기본 개념은 잘 숙지해두자.


참조 : 

https://en.wikipedia.org/wiki/Cache_replacement_policies

https://codeahoy.com/2017/08/11/caching-strategies-and-how-to-choose-the-right-one/

https://gomguard.tistory.com/115

https://onecellboy.tistory.com/260

https://dzone.com/articles/using-read-through-amp-write-through-in-distribute


Spring 3.1 버전부터 추가된 FlashMap 은 스프링에서 파라미터를 간편하게 전달하기 위한 자료구조이다.


주로 같은 도메인에서 Controller 간, 혹은 웹페이지에서 발생하는 Redirect 시 데이터 처리를 간단하게 하기 위한 목적으로 사용된다.


플래시 맵을 사용하는 용도는, URL 에 데이터를 노출시키지 않으면서 데이터를 전달하고 싶으면서도 Session 데이터에 넣기에 적합하지 않을 경우이다.

(Session 은 사용 후 값을 지워줘야 하므로 실수로 누락되는 경우를 방지해야하며 실제로 유저 정보들이 많이 관리되므로 가벼운 데이터의 경우에도 세션을 이용하기 부담스러운 경우가 많다.)


FlashMap 의 특징은 일반 Map 자료구조처럼 쉽고 간단하게 사용될 수 있으면서 사용되고 난 이후에는 Spring 에서 값을 자동으로 지워준다는 점에 있다.


즉, FlashMap 은 휘발성이며 사용하는 개발자 입장에서는 관리에 부담없이 가볍게 Attribute를 다룰 수 있다.


단, 휘발성이므로 서버가 지속적으로 관리하면서 사용해야 하는 공유 Attribute 에는 적합하지 않다고 한다.



참조 : 


https://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/servlet/FlashMap.html


https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-flash-attributes






웹 페이지를 구성하는 DOM Element 노드들은 트리 모양의 계층 구조를 갖고 있으며 DOM Element 와 연결된 Javascript 내부 동작 역시 이 구조에 대한 로직이 고려되어 있다.


이벤트 버블링과 캡쳐링은 Javascript 에서 주로 사용되는 Event Delegation Pattern 을 이해하는 기본적인 개념이다.


- 이벤트 버블링(Event Bubbling) 


웹페이지 내의 한 엘리먼트에서 이벤트가 감지되었을 때, 해당 엘리먼트의 계층구조를 따라 올라가면서 Root Element 까지 이벤트가 전달되는 것을 Event Bubbling 이라 한다.


이해를 돕기 위해 다음 코드를 확인해보자.


<div class="col-sm-1" onclick="alert('c')">
<div onclick="alert('b')">
<div onclick="alert('a')">
HELLO
</div>
</div>
</div>


위의 코드를 웹 페이지에서 확인해보면, HELLO 를 감싸고 있는 DOM 엘리먼트를 클릭하면 a - b - c 순서대로 3개의 Alert 창을 확인해볼 수 있다.


이처럼 이벤트 버블링(Bubbling)이란, 이벤트가 발생하는 가장 안쪽부터 바깥쪽, 하위 노드에서 상위노드로 이벤트가 전파(Propagation)되는 과정인 것이다.


하위 DOM Element 부터 전파되는 이벤트는 최종적으로 Document 객체까지 전달되며, 상위 Element 에서 이벤트 핸들러를 재정의해서 전파를 제어할 수 있다.


가령, 다음과 같은 코드에서 이벤트는 두번째 div 이상으로 전파되지 않는다.



<div class="col-sm-1" onclick="alert('c')">
<div onclick="event.stopPropagation()">
<div onclick="alert('a')">
HELLO
</div>
</div>
</div>


전파되지 않는 이유는 이벤트가 발생한 target Element 의 상위 Element 에서 onclick 메서드를 재구현하는데, event.stopPropagation() 함수를 이용해서 전파를 중단했기 때문이다.


이렇게 전파를 제어하는 것을 Stop Bubbling 이라고 한다.



- 이벤트 캡쳐링(Event Capturing)


이벤트 캡쳐링은 이벤트 버블링과 반대방향으로 이벤트가 전달된다.


다음 코드를 통해 이해해보자.


<div id="parent">
<div id="child">
HELLO
</div>
</div>
<script>
var parent = document.querySelector('#parent');
var child = document.querySelector('#child');
parent.addEventListener('click', function(){
alert("Parent clicked");
},true);
child.addEventListener('click', function(){
alert("Child clicked");
});
</script>


똑같이 계층 구조로 Element 들이 배치되어 있지만 이번에는 Parent 노드부터 이벤트가 전달된다.


이처럼 이벤트 캡쳐링(Event Capturing)이란, 상위노드부터 하위노드로 이벤트가 전달되는 형태를 말한다.


이 경우에 이벤트는 window 객체부터 차례로 아래 노드로 전파되며 addEventListener 의 3번째 인자로 capture 플래그를 두어 탐색 방향을 맞출 수 있다.


이벤트 캡쳐링의 경우 버블링보다는 덜 사용된다.



이벤트 버블링(Event Bubbling) 과 이벤트 캡쳐링(Event Capturing) 의 개념은 간단하지만, 이해하고 있지 않으면 은근히 프론트엔드 개발 시 삽질을 할 수 있는 부분이다.


잘 이해해두어 복잡한 UI 이벤트 처리 시에 헷갈리는 일이 없도록 하자.





본 포스팅에서는 현직 개발자에게도 생소하기 쉬운 쓰로틀링(Throttling)과 디바운싱(Debouncing) 테크닉에 대해 설명하고자 한다.


본래 Throttling 이란 주로 모바일 기기에서 많이 사용되는 용어로 성능을 위한 오버클럭(Overclock)이 디바이스에 무리를 주는 것을 방지하기 위해 고의로 성능을 낮추는 조절 방식을 말한다.


소프트웨어 적인 의미로도 Throttling 은 언급이 되곤 한다.


이 때에는 주로 트랜잭션을 처리하는 Middleware 나 네트워크 트래픽을 제어하는 ISP 에서 언급이 되며 UI 처리를 담당하는 프론트엔드(Frontend)에서도 사용된다.


프론트엔드(Frontend) 에서 쓰로틀링과 디바운싱은 어떤 경우에 사용될까?


가령 웹페이지를 구성하는데 해당 사이트는 다시 방문시 사용자가 읽던 포스트의 위치를 기억하고 그 페이지를 보여준다고 생각해보자.

페이지를 나눌 단위가 없으므로 스크롤 단위로 페이지 좌표를 서버에 기록하고자 한다면, 가장 단순한 방법은 Javascript 의 Scroll 이벤트를 이용해서 좌표를 저장하고 기록하는 방식이다.


이 경우 사용자의 스크롤링마다 이벤트를 발생시키면... 서버에도 클라이언트에도 매우 큰 부하가 발생되게 된다.

최악의 경우 페이지의 세로 좌표만큼 이벤트가 발생될 것이다.


예시는 최악의 구조와 최악의 경우를 가정한 것이지만, 중요한 점은 "이벤트의 오버클럭(Overclock)이 소프트웨어에 손상을 가져온다는 점" 이다.


이런 경우의 처리를 위해서도 쓰로틀링과 디바운싱 이라는 개념이 똑같이 적용되어 사용된다.


먼저 쓰로틀링(Throttling) 테크닉을 알아보자

쓰로틀링(Throttling) 을 이용하면 발생되는 이벤트 중간에 Delay 를 포함시킨다.


즉, Delay 이내로 연속적으로 발생된 이벤트에 대해서는 무시한다.


다음 코드를 보면 쉽게 이해될 것이다.




이런 종류의 테크닉은 특히 애니메이션을 구현하는 코드 등에서 많이 확인해볼 수 있다.


다음으로 디바운싱(Debouncing) 역시 쓰로틀링과 비슷하게 소프트웨어적인 오버클럭을 조절하는 테크닉이다.


하지만 쓰로틀링(Throttling) 과는 조금 다른 방법을 사용하는데, 쓰로틀링이 필터링(Filtering)의 방법을 사용한다면,


디바운싱(Debouncing)은 그루핑(Grouping)의 방법을 사용한다.


즉, 이벤트 핸들러가 주기적으로 여러 개의 발생한 이벤트를 하나로 묶어서 처리하는 방식이다.


이때, 먼저 발생한 이벤트가 처리를 대기하며, 대기하는 도중 새 이벤트가 발생하면 이전 이벤트의 대기를 취소(Cancel)하고, 해당 이벤트를 기준으로 다시 처리(Process)를 대기한다.

이렇게 특정 시간 동안 처리(Process)는 대기하게 되며 결과적으로는 일정한 시간 동안 연속적으로 발생한 이벤트는 마지막으로 발생한 이벤트 기준으로 처리된다.


여기서 Leading Edge 라는 디바운싱 테크닉을 이용하면 이 처리를 앞의 이벤트 기준으로 변경할 수 있으며 이 경우엔 쓰로틀링과 유사하게 동작하게 된다.

(나중에 발생하는 이벤트를 무시하는 방식은 같지만 첫 이벤트 처리가 딜레이 된다.)


다음 코드를 참조해보자.



쓰로틀링과 디바운싱은 생소하지만 알고보면 많은 이벤트 처리에 사용되고 있는 테크닉이다.

특히 UI를 처리하는 부분은 입력의 오버클럭을 감당하기 위해 없어서는 안되며 많은 라이브러리나 프레임워크에 이미 내장된 경우가 많으므로 잘 숙지해두는 것이 좋다.



좀 더 자세한 예시는 다음 링크가 가장 잘 되어 있는 듯 하다.

 : https://css-tricks.com/debouncing-throttling-explained-examples/


추가로 본 포스팅에선 이해를 돕기 위해 간단한 파이썬 코드로 예시를 작성했지만 실제 Javascript 에서 사용되는 코드의 예시는 다음을 참조해보자.

 : https://codeburst.io/throttling-and-debouncing-in-javascript-646d076d0a44




RDB 를 포스팅할 때 가장 먼저 정리해야 하는 부분인데 다소 순서가 밀렸다... 


이번 포스팅에서는 Database 를 다루는 데 있어서 가장 기본적인 Table 의 Key 에 대해 정리한다.


Database 에서 Key 의 의미는 테이블에서 각 데이터를 분류하는 기준의 역할을 한다.


MySQL 에서는 테이블의 데이터 들을 구분하기 위한 키의 종류로 다음과 같은 종류들을 사용한다.


(1) Key(Index)

 가장 일반적인 Key 는 DB 의 Index 와 동의어이다. Database 는 데이터의 검색을 위해 Index 를 색인으로 사용하므로 중요한 역할을 한다.

 중복을 허용하며 NULL 등의 허용도 가능하지만 NULL 이 허용될 경우... 색인에 있어 비약적인 성능 저하를 가져오므로 일반적으로 Nullable 한 데이터의 경우 Indexing 하지 않는다.

 단순히 Key, 즉 Index 로만 지정할 경우에는 별도에 제약조건(Constraint)을 가지지 않기 때문에 테이블 내에 데이터에 대해 엄격한 정합성이 요구될 경우에는 적합하지 않다.



(2) Primary Key

 일반적인 Key 는 Index 를 지칭하지만, 일반적으로 DB 설계를 할 때 Key 라고 하면 보통 PK 를 의미한다.

 NULL 을 허용하지 않고, Unique 성질을 지니므로 NOT NULL & UNIQUE 옵션이 포함되며 테이블 당 단 하나의 정의만 가질 수 있다.

 즉, PK 로 단 하나의 칼럼이 지정되어 있다면 해당 칼럼의 데이터는 Table 내에서 유일성이 보장되며 

 여러 개가 PK 로 지정되어 있다면 해당 Key 들의 조합에 대해 유일성이 보장된다.

 따라서 PK 는 같은 PK 를 갖는 행을 테이블 내에서 고유하게 만든다.


 기본적으로 Index 성질 역시 보장되기 때문에 검색 시 색인의 Key 가 되며, Constraint 를 갖기 때문에 다른 테이블과 JOIN 을 할 때 기준 값으로 사용된다.

 RDB 의 특징적인 데이터 정합성의 보장과 Key 값의 성질을 갖기 때문에 일반적인 설계에서도 가장 선호되는 Key 타입이다.



(3) Unique Key

 Unique Key 는 Uniqueness 를 지닌 Index를 말하며, Unique Index 라 부르기도 한다.

 PK 와 마찬가지로 중복성이 허용되지 않지만 NULL 에 대한 허용이 가능하다.

 테이블 당 여러개를 가질 수 있다.



(4) Foreign Key

 Foreign Key 란 JOIN 등으로 다른 DB 와의 Relation 을 맺는 경우, 다른 테이블의 PK를 참조하는 Column 을 FK 라고 한다.

 여기서 Foreign Key Relation 을 맺는 다는 의미는 논리적 뿐 아니라 물리적으로 다른 테이블과의 연결까지 맺는 경우를 말하며, 이 때 FK 는 제약조건(Constraint)으로의 역할을 한다.

 Foreign Key Restrict 옵션을 줄 수 있고 다음과 같은 옵션들이 있다.


  - RESTRICT : FK 관계를 맺고 있는 데이터 ROW 의 변경(UPDATE) 또는 삭제(DELETE) 를 막는다.


  - CASCADE : FK 관계를 맺을 때 가장 흔하게 접할 수 있는 옵션으로, FK 와 관계를 맺은 상대 PK 를 직접 연결해서 DELETE 또는 UPDATE 시, 상대 Key 값도 삭제 또는 갱신시킨다.

  이 때에는 Trigger 가 발생하지 않으니 주의하자.


  - SET NULL : 논리적 관계상 부모의 테이블, 즉 참조되는 테이블의 값이 변경 또는 삭제될 때 자식 테이블의 값을 NULL 로 만든다. UPDATE 쿼리로 인해 SET NULL 이 허용된 경우에만 동작한다.


  - NO ACTION : RESTRICT 옵션과 동작이 같지만, 체크를 뒤로 미룬다.


  - SET DEFAULT : 변경 또는 삭제 시에 값을 DEFAULT 값으로 세팅한다.



주로 PK 가 설계 시 많이 이용되지만, 정합성이 중요하지 않은 경우 Index 만 이용해서 테이블을 설계하기도 한다.

UNIQUE Index 는 주로 복잡한 테이블에서 부분적인 정합성을 살리기 위해 많이 이용된다.

그리고 FK 의 물리적 연결은 서버의 안정성을 위해 지양하는 편이 많다.


상황에 알맞게 적합한 Key 를 잡아 설계하는 것이 최선의 튜닝 기법이라고 생각된다.




Hibernate 를 이용한 토이프로젝트를 수행하면서... 큰 삽질을 해서 정리해보는 포스팅 ㅜㅜ


hbm2ddl.auto 설정은 hibernate 포함된 매핑 설정으로 Database 스키마 생성 스크립트를 만드는데 사용된다


시작시마다 Mapping 설정대로 Schema 세팅할 있는데 설정 값에 따라 다음과 같이 동작한다.


-      Create : Session Factory 실행될 스키마를 지우고 다시 생성. 생성 후에는 classpath import.sql 파일이 있는지 찾아 등록된 쿼리문을 실행한다.


-      Create-drop : 기본적으로 create 동일하지만 session 팩토리가 내려갈 db 스키마를 삭제한다. (이걸로 설정했다가 디비 날려먹었었다.)


-      Update ; 도메인 객체구성과 스키마를 비교해서 도메인 객체에 맞춰서 db 스키마를 변경한다. 데이터나 스키마를 지우지 않는다.


-      Validate : 도메인 객체구성과 db스키마가 같은지만 확인할 변경하지 않는다. 다를 session Factory 시작시 확인하고 예외를 발생시킨다.


다음은 Hibernate 사용시 알아두어야 하는 JPA 프로퍼티들이다.





COMET 이란 2006년 알렉스 러셋(Alex Russel)이 정의한 용어로, 브라우저가 HTTP 요청에 대해 데이터를 푸시하는 방법을 고안한 웹 모델이다.


일반적인 웹모델은 널리 알려진 바 대로 서버와 클라이언트 브라우저간 상태를 유지한 통신이 불가능하다. 


COMET 은 이러한 HTTP 의 본질적 한계를 어느정도 극복하고자 만든 Web Application Model 이라고 생각하면 된다.


가령 브라우저가 지속적으로 서버에 데이터를 받아야할 필요가 있을 때 서버의 데이터가 업데이트 되지않았다면 이는 무의미하다.

즉, 클라이언트의 입장에서 갱신이 필요한 절대적인 시점은 무조건 서버의 데이터가 변경되었을 때가 된다.


COMET 은 간단하게는 Client 로 유의미한 메시지를 전달할 때까지 HTTP 응답을 지연시키는 기술이다.


좀 더 정확히는 서버가 클라이언트의 요청에 응답할 때 응답을 "늘어뜨리는 방법" 을 이용해서 긴 시간동안 브라우저가 접속을 끊지않고 서버의 응답을 대기하게 만든다. 


즉, Long polling 과 원리가 같다.

(Long Poll – 서버측에서 단순히 클라이언트 측에 대한 연결을 길게 유지함으로써 지정한 기간 내에 정보가 있으면 응답을 전달한다. 메시지 양이 많으면 Polling 과 차이가 없으며 지정한 시간이 초과되어 끊기면 다시 요청하는 말그대로 긴 – Polling 이다.)


클라이언트는 Long polling 을 해주고, 그 시간 동안 서버는 서버에서 발생한 이벤트 정보 등도 같이 끼워넣어줌으로써 이른바 "HTTP 푸시" 를 흉내내게끔 한다.


COMET 모델에서 서버는 비동기 방식을 취하고, 클라이언트가 다양한 테크닉으로 푸시를 받을 수 있는 구조를 취하는 경우가 일반적이다.


이에 Javascript 레벨에서 사용되는 테크닉으로, Hidden Iframe 영역(Forever frame)을 할당하고 서버측에서 발생하는 이벤트별로 <script> 태그 내에 데이터를 채워넣는 방식 또는 Ajax 의 long polling 방식, 그리고 Active X 를 이용하는 방식을 사용하기도 한다.


COMET 모델에서 서버와 클라이언트가 통신하기 위해 JSONP 라는 방식을 사용하는데, 이는 JSON 규격의 데이터로 통신을 하되 Client 로부터 전달받은 Callback 함수를 호출하게끔 하는 방식이다.


이렇게 되면 브라우저는 Callback 함수로 감싸여진 Json 데이터를 이용해서 <script> 또는 XHR 을 구성하며 해당 리소스를 읽고 수행하게 된다.


이처럼 COMET 모델을 이용하면 서버에서 발생한 이벤트를 Client 의 추가 요청없이 송신할 수 있다. 



현재는 Websocket 및 HTML5에서 표준화된 Server-sent Event 와 연관되어 발전해가고 있다.





+ Recent posts