xml과 html의 차이 Java 스크랩

XML(eXtensible Markup Language)은 HTML(Hyper Text Markup Language)과 함께 마크업(Markup) 언어의 일종입니다.
마크업 언어란 웹 페이지를 만드는데 사용되는 프로그래밍 언어로 태그라는 요소를 사용하여 구성합니다.

 

우리가 익숙한 HTML은 태그를 사용하여 웹 페이지를 보기좋게 구성, 표현합니다.
그러면 XML은 어떤 역할을 하느냐?
XML은 HTML처럼 웹 페이지의 표현보다는 웹 페이지에 표시된 데이터의 효율적인 사용을 주목적으로 한다는 점에서 두 언어의 근본적인 차이점이 있습니다.

 

즉, HTML로 만든 웹 페이지는 웹 페이지의 표현에 치중하지, 그 웹 페이지에 표시된 데이터의 효율적인 사용에는 관심을 두지 않습니다.
이런 HTML의 한계를 극복하여 표시된 데이터를 보다 효율적으로 사용하기 위해서 등장한 언어가 바로 XML인 것입니다.

 

XML의 구체적인 사용 예를 본다면
`검색의 효율을 올리기 위한, 웹 페이지 검색에 대한 데이터의 효율적인 추출
`웹 페이지를 이용한 전자 상거래 데이터의 전송
`웹 페이지와 데이터 베이스 간의 데이터의 교환
이런 예들을 들 수가 있는데 한마디로 웹 페이지 데이터의 효율적인 사용에 촛점이 맞춰져 있습니다.

 

혹자는 "HTML은 이제 사라지고 곧 XML만으로 웹 페이지를 만드는 시대가 올 것이다." 이렇게 떠들고 있는데 이것은 XML의 기본적인 개념조차 모르는 무식의 소치라 할 것입니다.
앞서도 말씀드렸지만 HTML은 웹 페이지의 표현을 주목적으로 하고, XML은 웹 페이지에 표시된 데이터의 효율적인 사용을 주목적으로 하므로 두 언어 간의 사용 목적과 등장 배경에는 근본적인 차이점이 존재합니다.

 

즉, 두 언어는 서로 상호 보완적인 측면으로 병행하며 발전할 성질의 것이지, 어느 한 언어가 다른 언어를 완전히 잠식하고 그 언어만 단독으로 발전하는 그런 관계는 애초부터 성립할 수조차 없다는 것입니다.

 

물론 XSL로 XML로 만든 웹 페이지를 HTML로 만든 웹 페이지처럼 보기 좋게 구성할 수도 있지만, 그렇다하더라도 근본적인 목적은 어디까지나 웹 페이지에 표시된 데이터의 효율적인 사용이고, 모든 웹 페이지가 웹 페이지에 표시된 데이터의 효율적인 사용을 목적으로 만들어지지도 않기 때문에 그런 웹 페이지는 당연히 계속 HTML을 사용하여 만들어지게 될 것이기 때문입니다.


출처 - http://k.daum.net/qna/view.html?category_id=QCF003&qid=3qBda&q=xml&srchid=NKS3qBda


Spring이란? Java 스크랩

Spring Framework Summary

 

- IOC ( Inversion Of Control )과 DI ( Dependency Injection)에 기반을 둔 자바 어플리케이션 프레임워크

- IOC : 자신의 컨트롤을 인터페이스 혹은 설정을 통하여 역으로 위임하는 사상으로 Interface의 구현 또는 Operation의 Overriding을 통해서 정의 가능하다.

- DI :  Code의 수행 시점에서 의존성 관계를 정의(Dependency를 Inject)하는 기법. 예를 들어, FileLister의 경우, LocalFileFinder, RemoteFileFinder등의 Finder Interface의 구현을 FileLister에 Set 혹은 Construction를 통하여 건내 준다는 사상.


6개의 중요 모듈로 구성
- Spring Core : IoC 컨테이너로 스프링의 중요 컴포넌트들을 구동/관리 역할 모듈
- Spring DAO : JDBC 및 Transaction 관리 모듈
- Spring ORM : Hibernate, iBatis 등의 유명 프레임워크와 연계된 OR Mapping 모듈
- Spring AOP : Aspect J Integration 으로 Aspect Oriented Programming을 반영
- Spring J2EE : JMX, JMS, J2EE등의 EJB Feature를 이용하기 위한 Extension
- Spring WEB : Web MVC Framework Integration을 기반으로 Struts, WebWorks등의 Web관련 프레

 

3가지의 대표적인 사용방식(사용방식에 따라 모듈 구성이 틀릴 수 있음 )

- Spring middle Tier using 3rd Party Web Framework
      + Struts, Tapestry 등의 Web 프레임워크에 스프링을 통합하여 사용하는 경우


- Remote Usage
      + Spring을 원격 호출되는 서버 어플리케이션 구현에 사용하는 경우


- EJB Wrapping existing POJO
      + EJB환경을 이용하여 기존 POJO를 EJB로 재구성하는 경우 

 


POJO란? Java 스크랩

 

더 자바답게! 더 슬림하게! 다이어트 POJO 프로그래밍

지난 몇 년간 EJB3를 포함한 많은 자바의 새로운 기술과 제품들은 저마다 POJO 프로그래밍의 지원을 주요 장점으로 내세우며 등장했다. 그러나 POJO 프로그래밍이 과연 무엇이고 어떤 이득을 안겨줄 수 있는지에 대해 명확히 설명하는 것은 사실 쉽지 않다. 이 글에서는 POJO 프로그래밍이 왜 중요한지 살펴보고 그것을 통해 기존의 무겁고 지저분한 코드를 어떻게 깔끔하고 군살 없는 코드로 만들 수 있는지를 알아보자.

 

 

POJO는 ‘Plain Old Java Object’의 약자이다. 이를 번역하면 ‘평범한 구식 자바 오브젝트(객체)’라고 할 수 있겠다. 도대체 평범하고 구식인 자바 오브젝트가 뭐가 다르고 특별해서 POJO라고 부르는 것일까? 그럼 평범하지 않은 최신의 자바 오브젝트는 또 무엇인가?

 

 

POJO란 무엇인가?

POJO를 이해하려면 POJO라는 단어가 만들어진 역사적 배경을 살펴볼 필요가 있다. POJO는 마틴 파울러가 2000년 가을에 열렸던 어느 컨퍼런스의 발표를 준비하면서 처음 만들어낸 말이다. 마틴 파울러는 EJB(Enterprise JavaBean)보다는 단순한 자바 오브젝트에 도메인 로직을 넣어 사용하는 것이 여러 가지 장점이 있는데도 왜 사람들이 그 EJB가 아닌 ‘평범한 자바 오브젝트’를 사용하기를 꺼려하는지에 대해 의문을 가졌다. 그리고 그는 단순한 오브젝트에는 EJB와 같은 그럴듯한 이름이 없어서 그 사용을 주저하는 것이라고 결론 내렸다. 그래서 만든 단어가 POJO라는 용어인 것이다. POJO 기반의 기술을 사용한다고 말하면 왠지 첨단 기술을 사용하는 앞선 개발자인 듯한 인상을 주기 때문이다. 
이 POJO라는 용어를 만들어낸 전략은 매우 성공적이었다. EJB의 문제점과 한계를 느낀 많은 개발자들은 새로운 기술처럼 보이는 POJO 프로그래밍이라는 것에 관심을 가지게 되었고, POJO 기반의 프로그래밍 기술이 EJB의 강력한 대안으로 등장하기 시작했다. POJO 기반의 프레임워크, POJO 애플리케이션을 위한 플랫폼 등이 점점 인기를 끌게 되었고, 결국 POJO가 배제하려고 했던 EJB는 POJO 기반의 기술에 밀려 이제 레거시 기술로 사라질 위기에 처했다. 그렇다면 단지 EJB를 사용하지 않으면 모두 POJO라고 할 수 있을까? 그렇지는 않다. POJO 프로그래밍이라는 개념은 단지 ‘EJB가 아닌 자바’ 이상의 특징을 가지고 있는 프로그래밍 모델이다. POJO 기반의 개발은 생각보다 단순하지 않다. 
POJO를 좀더 이해하려면 EJB의 장단점을 함께 이해해야 한다. 그것은 POJO 프로그래밍이 다시 EJB 시대 이전으로 돌아가자는 것이 아니고, EJB를 넘어 그보다 더 앞으로 나아가자는 것이기 때문이다.


EJB와 엔터프라이즈 서비스

자바에서 EJB 기술의 등장은 필연적인 것이었다. 기업의 IT 시스템은 점점 그 중요성이 증대되고 그에 따라 점점 복잡한 기술이 요구되었으며 자바의 기초적인 JDK만으로는 그것을 충족시킬 수 없었다. 서버 기반의 자바 기술인 J2EE(Java2 Enter pise Edition)가 등장했지만 Servlet, JSP 레벨의 최소한의 서버 프로그래밍 인터페이스만 가지고는 복잡한 엔터프라이즈 애플리케이션을 제작하는 데 부담이 적지 않았다.
엔터프라이즈 시스템의 복잡도는 두 가지 다른 영역에서 증대되었다. 하나는 기업 업무처리의 IT 시스템에 대한 의존도가 높아지면서 시스템이 다뤄야 하는 비즈니스 로직 자체가 점차로 복잡해진 것이다. 또 다른 하나는 많은 사용자의 처리요구를 빠르고 안정적이면서 확장 가능한 형태로 유지하기 위해 필요한 로우레벨의 기술적인 처리 요구들이다. 단순히 DB와 연동하는 수준의 C/S 기반의 스탠드얼론(standalone) 애플리케이션과는 달리 서버에서 동작하는, 그것도 웹 기반으로 많은 처리 요구를 받는 시스템에는 감당해야 할 중요한 기술적인 요구사항들이 많다. 대표적으로 트랜잭션 처리, 상태 관리, 멀티스레딩, 리소스 풀링, 보안 등이 있다. 
애플리케이션 로직의 복잡도와 상세 기술의 복잡함을 개발자들이 한 번에 다룬다는 것은 쉬운 일이 아니었다. 한 개발자가 보험업무와 관련된 계산 로직을 자바로 어떻게 구현해야 하는지에 집중하면서 동시에 시스템 레벨에서 멀티 DB로 확장 가능한 트랜잭션 처리와 보안 기능을 멀티스레드 세이프하게 만드는 것에 신경 써야 한다면 여간 부담되는 게 아닐 것이다.
EJB는 이런 문제를 다루기 위해 등장했다. EJB 1.0의 스펙이 제시한 EJB의 비전은 ‘EJB는 애플리케이션 개발을 쉽게 만들어 준다. 애플리케이션 개발자는 로우레벨의 기술들에 관심을 가질 필요도 없다’였다. 애플리케이션 개발자들은 다뤄야 하는 해당 도메인과 비즈니스 로직에만 집중하면 된다는 것이었다. 게다가 EJB는 독립적으로 개발한 컴포넌트들을 서버에 자유롭게 배포하고 서로 연동해 사용하게 하는 컴포넌트 기반의 개발 모델을 제시할 뿐더러, 여러 대의 서버에 분산되어 있는 모듈간의 리모팅 처리도 개발자들이 거의 신경 쓰지 않고 개발할 수 있게 했다. 더 나아가 벤더별로 제각각 발전시켜 혼란에 빠지기 쉬운 자바의 서버 기술을 일관성 있게 구현하게 지원하므로 특정 서버에 종속되지 않고 서버간의 이동성(portability)을 보장해 준다고 약속했다. 
과연 EJB는 스펙을 통해 제시한 그런 환상적인 기대를 충족시켰는가? 이제는 누구나 다 잘 알고 있듯이 현실에서는 그렇지 못했다. EJB는 불필요할 만큼 과도한 엔지니어링으로 실패한 대표적인 케이스였다. EJB에서는 현실에서 1% 미만의 애플리케이션에서만 필요한 멀티 DB를 위한 분산 트랜잭션을 위해 나머지 99%의 애플리케이션도 무거운 JTA 기반의 글로벌 트랜잭션 관리 기능을 사용해야 했다. EJB의 혜택을 얻기 위해 모든 기능이 다 필요하지도 않은 고가의 WAS(CPU 당 몇 백에서 몇 천만 원씩 하는)를 구입해야 했고, 고급 IDE의 도움 없이는 손쉽게 다룰 수 없는 복잡한 설정 파일 속에서 허우적대야 했다. EJB 컴포넌트는 컨테이너 밖에서는 정상적으로 동작할 수 없으므로 개발자들은 끝도 없이 반복되는 수정-빌드-배포-테스트의 지루한 과정으로 많은 시간을 낭비해야 했고, 간단한 기능에 대해서조차 자동화된 테스트를 만드는 것은 거의 불가능에 가까웠다. 테스트는 서버에 배치 후에 대부분 수동으로 해야 했고, 느린 배포 작업 탓에 그나마도 자주 반복되기 힘들게 만들었다. 특별한 경우가 아니라면 그다지 장점이 없는 EJB의 원격분산 모델은 성능을 떨어뜨리고 서버의 복잡도만 증가시켰다. 가장 최악의 문제점은 EJB 스펙을 따르는 비즈니스 오브젝트들은 객체지향적인 특징과 장점을 포기해야 했다는 것이다. EJB빈은 상속과 다형성 등의 혜택을 제대로 누릴 수 없었다. 간단한 기능 하나를 위해서도 많은 인터페이스와 EJB 의존적인 상속 등을 사용해야 했다. EJB 옹호자들 사이에서조차 외면 받아온 엔티티빈에 대해 말하는 것은 시간 낭비일 것이다. 상태 있는 세션빈(SFSL)도 기술적인 한계와 비효율성으로 인해 현장에서는 많이 사용되고 있지 않다. 그나마 오랫동안 사용된 EJB는 상태 없는 세션빈(SLSF) 뿐이다.
그럼에도 EJB가 계속 사용되었던 이유는 무엇일까? 그것은 EJB가 스펙에서 제시한 그 몇 가지 장점 때문이었다. 엔터프라이즈 애플리케이션에서 반드시 필요로 하는 주요한 엔터프라이즈 서비스들을 애플리케이션 코드와 분리해서 독립적인 서비스로 사용할 수 있게 만들어줬다는 점이다. 비록 불완전하고 불필요한 복잡도가 남아있긴 했지만 선언적인 트랜잭션 관리(Declarative Transaction Management)나 역할 기반의 보안(Role based Security) 기능들을 제공했다. 비즈니스 오브젝트를 배포하고 관리하는 컨테이너를 제공하고 기본적인 스레드 관리, 인스턴스/리소스 풀링을 제공하는 등의 것들이다. 한편으로는 ‘개발자들이 로우레벨의 기술적인 문제에 신경 쓰지 않고 비즈니스 로직에 충실히 개발하게 함으로써 애플리케이션 개발을 손쉽게 만들어 준다’는 처음 약속을 어느 정도 지켰다고 볼 수 있다. 하지만 EJB의 문제는 앞서 지적한 것처럼 한편으로는 애플리케이션 개발의 복잡도를 제거하면서 다른 한편으로는 더 많은 문제와 복잡성을 가지고 왔다는 것이다. 
결국 EJB는 형편없는 생산성과 느린 성능, 불필요한 기술적인 복잡도, 벤더 사이의 알력으로 과도하게 높아진 스펙 등으로 인해 자바의 엔터프라이즈 개발에 대한 불신을 가중시켰다. 마침내 마틴 파울러를 비롯한 많은 오피니언 리더들은 EJB와 같은 잘못 설계된 과도한 기술을 피하고, 객체지향 원리에 따라 만들어진 자바 언어의 기본에 충실하게 비즈니스 로직을 구현하는 일명 POJO 방식으로 돌아서야 한다고 지적하고 나섰다. POJO 방식의 개발은 EJB가 잃어버린 소중한 가치인 객체지향적인 설계와 자동화된 테스트의 편의성, 개발생산성 등을 회복시켜 줄 수 있는 길이기 때문이다.

 

 

POJO 프레임워크

앞에서 강조한 것처럼 EJB를 사용하지 말고 POJO를 쓰자는 것이 EJB 이전의 방식으로 돌아가는 것을 의미한다면 또 다른 문제가 발생할 수밖에 없다. 여전히 복잡한 로우레벨의 API를 이용해 코드를 작성해야 하고, 많은 기술적인 문제를 애플리케이션 코드에 그대로 노출시켜 개발해야 한다면 기껏 POJO로의 복귀 덕분에 얻은 많은 장점들을 놓칠 수밖에 없다. 
그래서 등장한 것이 바로 POJO 기반의 프레임워크이다. POJO 프레임워크는 POJO를 이용한 애플리케이션 개발이 가진 특징과 장점을 그대로 살리면서 EJB에서 제공하는 엔터프라이즈 서비스와 기술을 그대로 사용할 수 있도록 도와주는 프레임워크이다. 나아가 이는 기존의 EJB에서보다 훨씬 더 세련되고 나은 방법이다. 많은 POJO 프레임워크가 있지만 그 중에서 가장 대표적인 것을 꼽으라면 하이버네이트와 스프링을 들 수 있다.
하이버네이트는 EJB의 엔티티빈이 제시했던 컨테이너가 관리하는 퍼시스턴스 기술(Container Managed Persistence)과 오브젝트-관계형 DB 매핑(Object Relational Mapping) 기술을 순수한 POJO를 이용해 사용할 수 있게 하는 POJO 기반의 퍼시스턴스 프레임워크이다. 하이버네이트는 사실 엔티티빈이 제공했던 것과는 비교할 수 없을 만큼 더 편리하고 세련된 방식으로 퍼시스턴스 기능을 제공한다. 굳이 컨테이너 위에서 동작시킬 필요도 없고, 이상적인 매핑을 위해 포기했던 많은 기능과 성능을 객체지향 DB에 적합하게 최적화한 기능을 통해 JDBC API를 직접 사용해 개발하는 것 못지않은 성능과 복잡한 퍼시스턴스 로직을 개발 가능하게 해줬다. 가장 중요한 점은 하이버네이트가 사용하는 POJO 엔티티들은 EJB의 엔티티빈과 달리 객체지향적인 다양한 설계와 구현이 가능하다는 점이다. 엔티티의 상속, 다형성, 밸류 오브젝트, 사용자정의 타입 등을 어떠한 기술적인 손해 없이도 그대로 퍼시스턴스 매핑용 오브젝트로 사용할 수 있게 한다. 
스프링은 세션빈이 제공하던 중요한 엔터프라이즈 서비스들을 POJO 기반으로 만든 비즈니스 오브젝트에서 사용할 수 있게 한다. 대표적인 것이 선언적인 트랜잭션 서비스와 보안이다. 또한 EJB와 마찬가지로 오브젝트 컨테이너를 제공해서 인스턴스의 라이프사이클을 관리하고 필요에 따라 스레딩, 풀링 및 서비스 인젝션 등의 기능을 제공한다. 또한 OOP를 더 OOP답게 사용할 수 있게 하는 AOP 기술을 적용해서 POJO 개발을 더 쉽게 만든다.


POJO vs. 짝퉁 POJO

POJO 프로그래밍의 진정한 가치는 자바의 객체지향적인 특징을 살려 비즈니스 로직에 충실한 개발이 가능하도록 하는 것이다. 그러면서 복잡한 요구조건을 가진 엔터프라이즈 개발의 필요조건을 충족시킬 수 있도록 POJO 기반의 프레임워크를 적절히 사용하는 것이 요구된다. 문제는 단지 POJO 프레임워크로 잘 알려진 제품을 사용하기만 하면 자동으로 POJO 개발을 하고 있다고 생각하는 경우가 많다는 것이다. 
스프링과 하이버네이트가 한창 인기를 끌기 시작할 때 EJB 기반으로 구현된 애플리케이션에 스프링과 하이버네이트를 적용했다고 해서 주목받던 어느 오픈소스 제품이 있었다. POJO 기반 서버 애플리케이션의 좋은 샘플이라고 생각한 필자와 동료들은 그 소스를 가져다가 한번 살펴봤는데, 정작 그 소스를 보고는 놀라지 않을 수 없었다. EJB를 제거하고 POJO 기반의 프레임워크를 적용했다고는 하지만 사라진 것은 단지 EJB 관련 클래스와 인터페이스 정도이고 그 외에 EJB로 개발할 때 가졌던 모든 코드와 스타일을 그대로 가져다가 억지로 POJO 프레임워크에 구겨 넣은 것을 발견했기 때문이다. 그들이 말하는 POJO 프레임워크 기반의 개발이란 단지 POJO 프레임워크 위에서 동작하기만 하면 그 오브젝트의 설계와 구현은 어찌되든 상관없는 형태였다. 이는 자바가 처음 등장했을 때 자바로 개발한다고 하면서, 실제로는 C에서 쓰던 절차적인 방식(객체지향적인 모든 특성 무시)으로 구현했던 경우와 다를 게 없었다.
필자는 그런 POJO 애플리케이션을 짝퉁 POJO라고 부르고 싶다. 결과적으로 그런 개발은 POJO 프로그래밍이 주는 장점을 제대로 살릴 수 없고 오히려 배제되어야 할 또 다른 복잡함을 낳기 때문이다. <리스트 1>은 최근에 어느 프로젝트에서 스프링을 이용해 개발했다고 소개한 코드를 간략하게 옮겨놓은 것이다.

<리스트 1> 잘못된 POJO 기반 코드의 예

class MyService {
   private MyDAO myDAO;
   private XXDao xxDAO;
   … 
     public MyVo foo(UrVO urVo) throws MyException
    {
        Connection con = null; 
        try {
            con = DBUtil.getConnection();
       con.setAutoCommit(false);

       if (xxDAO.check(urVo))
            return myDAO.foo(con, urVo);
       
      else
        return myDAO.boo(con, urVo);
      }
 catch (MyException e) {
   con.rollback();
     throw e;
  }
   catch (Exception e) {
     throw new MyException(e, "XXX00001");
      con.rollback();
         }
          finally {
           con.commit();
             DBUtil.close(con);
         }
     }

}


class MyDAO { 
public void foo(Connection con, UrVO urVO) throws MyException {

           PreparedStatement pstmt = null;
           try {
              pstmt = new LoggablePreparedStatement(con, QueryFactory.getInstance().getQuery("FOO"));
          pstmt.setInt(1, urVO.getSeq());
          if (pstmt.executeUpdate() != 1) {
                throw new MyException("SVM00009");
}
} catch (MyException e) {
       throw kble;
} catch (Exception e) {
       throw new MyException(e);
} finally {
       DBUtil.close(pstmt);
}
}

}

이 코드는 물론 스프링의 IoC/DI 컨테이너에 올라가서 빈(bean)으로 등록되어 Setter 인젝션 방식으로 사용되기는 할 것이다. 그럼 과연 이 코드가 POJO라고 말할 수 있을까? 물론 EJB를 사용하지 않았고 특정 환경에 종속적인 것처럼 보이지도 않는다. 또한 POJO 프레임워크의 대표격인 스프링 프레임워크를 사용해 만들어졌다. 하지만 이 코드는 POJO 프로그래밍의 장점을 거의 살리지 못한 레거시 코드일 뿐이다. 필자는 POJO 기반의 코드인지 아닌지를 확인하기 위해 다음의 중요한 두 가지 기준을 적용한다.
첫째는 객체지향적인 설계원칙에 충실하도록 개발되어 있는지 여부이다. POJO의 자바 오브젝트라는 것은 단지 자바 언어 문법을 지켜 만들었다는 뜻이 아니다. 객체지향 언어로서의 자바 오브젝트의 특징을 가지고 있는지가 중요하다. POJO 코드가 객체지향적인 원리에 따라 설계되어 있지 않고 더 나아가 적절하게 리팩토링하는 것도 어려운 구조라면 POJO로 개발했다는 것이 주는 가치는 거의 없다고 본다. EJB를 사용하지 않으므로 오히려 코드가 <리스트 1> 같은 식으로 바뀌었다면 그것은 POJO 개발이라고 볼 수 없다. 끊임없이 반복적으로 등장하는 템플릿 코드와 테스트하기 힘든 구조, 확장이나 재활용의 어려움 등이 코드에 그대로 남아있다면 EJB의 문제점을 여전히 안고 있는 것이다. 
둘째는 테스트 코드 개발의 용이성이나 테스트 코드를 잘 작성했는지의 여부이다. EJB를 버리고 POJO 기반으로 개발한다고 하면서도 여전히 수정-빌드-배포-테스트라는 방식을 탈피하지 못하고 있다면 EJB로 개발했던 시절과 대체 무엇이 다를까? 잘 만들어진 POJO 애플리케이션은 자동화된 테스트 코드 작성이 편리하다. 코드 작성이 편리하면 좀더 자주 꼼꼼하게 만들게 되고 반복적으로 실행할 수 있으므로 코드 검증과 품질 향상에 유리하다. 또한 잘 만들어진 테스트 코드베이스가 있다면 리팩토링할 여유가 생겨 POJO 코드를 더 나은 설계구조로 변경할 가능성도 높아진다.

 

POJO로의 변환

<리스트 1>의 코드를 스프링의 POJO 프로그래밍 모델에 따라 수정해 보자. DAO 코드의 가장 큰 문제점은 JDBC의 오래된 코드 스타일을 그대로 사용하고 있다는 것이다. 따라서 try/catch/ finally의 전형적인 템플릿 코드가 실제 DAO 로직보다 더 많은 라인을 차지하고 있다. 또 Query를 불러오는 부분이 싱글톤을 사용하고 있다. 그나마 JDBC 코드를 간략하게 작성하도록 돕는 유틸리티 클래스를 사용했지만 정적 메소드를 이용했다. 싱글톤과 정적메소드는 테스트 코드를 만드는 데 가장 큰 장애물이다. 테스트를 쉽게 하기 위해 모의객체(mock object)로 변환하는 것이 불가능하기 때문이다. 객체지향적인 설계방식을 따른다면 Query를 가져오는 기능을 인터페이스로 만들어 사용하게 하고 이를 구현한 오브젝트를 DAO에서 참조할 수 있도록 하는 것이 바람직하다. 또한 템플릿 스타일의 과도한 코드를 제거하고 반복적인 JDBC 워크플로우를 제거하려면 콜백 방식으로 구현하는 게 좋다. 그러면 DAO의 데이터액세스 로직과 JDBC 처리 워크플로우를 구분할 수 있다. <리스트 2>는 이렇게 스프링을 이용한 POJO 스타일로 수정된 코드이다.

<리스트 2> 수정된 MyDAO

public class MyDAO {
              private DataSource dataSource;
              private SimpleJdbcTemplate jdbcTemplate;
              private QueryFactory queryFactory; 
              // setter methods
              public void foo(UrlVo urlVo) {

jdbcTemplate.update(queryFactory.getQuery("FOO"), urlVo.getSeq());
}
}

MyDAO는 DataSource, QuereyFactory라는 협력객체를 인터페이스를 통해 액세스하므로 해당 오브젝트의 구현에 상관없이 동작할 수 있다. DataSource가 개발용에서 테스트용으로 또 실제 운영서버로 바뀐다고 하더라도 DAO는 그 부분에 신경 쓰지 않고 클래스의 목적인 데이터로직을 구현하는 데만 충실하게 만들어져 동작할 수 있게 되었다. 테스트를 위해 실제 DB가 아닌 Fake DB나 Embedded DB를 적용한다면 그 DB 설정을 돌려주는 적절한 DataSource를 MyDAO가 사용하도록 스프링을 통해 설정하면 그만이다. 
또 JdbcTemplate이라는 JDBC 워크플로우를 제공하는 템플릿 기반의 Helper 클래스를 사용해서 반복적으로 등장하는 JDBC의 try/catch/finally 작업을 DAO에서 제외하고 순수하게 데이터 처리와 관련된 핵심 로직만 사용하도록 정리했다. 
결과적으로 코드는 깔끔해지고 여러 클래스에 거쳐 나타나는 지저분한 중복은 제거되었다. 또한 DAO 오브젝트의 역할을 넘어선 것들은 의존하는 오브젝트로 분리하고 그 구현에 종속되지 않도록 인터페이스를 사용하게 했으므로 객체지향적인 설계에 충실한 오브젝트의 설계와 구현에 가깝도록 만들어졌다. 
이번에는 MyService를 살펴보자. MyService의 가장 큰 문제는 무엇인가? 그것은 MyService는 비즈니스 로직을 구현한 클래스임에도 불구하고, 실제로 코드 안에는 그와 상관없는 데이터액세스와 관련된 코드들이 덕지덕지 붙어 있다. MyService에 나타난 커넥션과 트랜잭션 처리 코드들은 어찌 보면 어쩔 수 없는 선택으로 생각할 수도 있다. DAO를 분리해 놓은 상태로, MyService에서 여러 개의 DAO를 호출해 처리하는 결과를 하나의 커넥션과 트랜잭션으로 묶으려면 MyService 레벨에서 처리해야 하기 때문이다. 그렇지 않고 DAO 메소드 단위로 커넥션과 트랜잭션을 다루면 더 심각한 결과를 가져온다. 하지만 결과적으로 MyService는 DB 처리 코드와 로직 코드가 짬뽕되어 있는 지저분한 코드가 되었고, DB 관련 코드와 구현에 종속이 되었으므로 MyService는 객체지향적인 장점을 살려 재활용되거나 발전하는 데 극히 제한을 받게 된다. 만일 트랜잭션 처리가 JDBC 방식에서 JTA로 바뀌었다면? MyService처럼 구현한 모든 서비스/비즈니스 로직 코드를 일일이 수정해야 하는 중노동에 시달려야 한다. 하나의 클래스에 여러 가지 레이어의 기술이 짬뽕되고 책임이 중복되어 나타나며 한 가지 기능을 수정하기 위해 수많은 클래스를 수정해야 한다면 이것이 과연 POJO를 지지하는 사람들이 기대했던 바로 그 POJO 프로그래밍의 장점이라고 할 수 있을까?

<리스트 3> 수정된 MyService

class MyService {
     private MyDAO myDAO;
     private XxDAO xxDAO;
// setter methods
public void foo(UrVo urVo) {
    if (xxDAO.check(urVo))
       return myDAO.foo(con, urVo);
else
      return myDAO.boo(con, urVo);
 }

}


MyService를 순수한 비즈니스 로직에 충실한 POJO 기반으로 변경하려면 스프링과 같은 POJO 프레임워크의 도움이 절실히 필요하다. 겉으로 드러나는 DB 커넥션, 예외처리, 트랜잭션과 관련된 부분을 비즈니스 로직을 구현한 MyService에서 분리하기 위해서는 AOP 기술의 도움이 필요하기 때문이다. <리스트 3>은 스프링의 AOP로 선언적 트랜잭션 관리 기능을 적용해 변경한 MyService 코드이다. 
<리스트 1>에서 보았던 MyService의 모든 지저분한 DB와 트랜잭션 처리 블록이 모두 제거되었다. 남은 것은 MyService의 비즈니스 로직에 충실한 코드들뿐이다. 필요에 따라 적절한 DAO를 호출해서 퍼시스턴스 관련된 기능을 DAO를 통해 처리하는 것만 있다. 이는 객체지향적인 설계 모델에 충실하게 만들어져 있다.
한 가지 남은 문제는 테스트 유용성인데, MyService의 메소드를 테스트하기 위해서는 MyDAO, XxDAO가 필요하다. DAO는 DB를 역시 필요로 하므로 MyService를 테스트하기 위해 그 메소드를 호출하면 2개의 DAO 코드와 DB까지 동작이 필요하기 때문이다. DB까지 연동하는 테스트는 그 데이터 준비도 만만치 않거니와 시간도 많이 걸린다. 따라서 테스트를 만들고 자주 수행하는 데 어려움을 준다.
이를 위해 MyDAO를 다시 생각해 볼 필요가 있다. MySer vice 입장에서 MyDAO는 오브젝트를 장기간 보존하고 그것을 다시 조회하도록 돕는 퍼시스턴스 기능의 필요에 따라 사용하는 대상이다. 그 구현이 어떻게 되는지는 중요하지 않을 뿐더러 퍼시스턴스 구현이 필요하면 바뀔 수도 있다고 가정하면 지금과 같은 MyDAO의 클래스를 직접 액세스하는 구조는 바람직하지 않다. 전략패턴(Strategy Pattern)의 개념을 적용해서 MyDAO를 인터페이스와 구현으로 분리하고 MyService는 MyDAO 인터페이스를 사용하도록 수정하면 이 문제를 모두 해결할 수 있다. 먼저 MyDAO 인터페이스를 정의한다.


interface My DAO {
void foo(UrVo);
}

그리고 이를 구현하는 클래스를 만든다.

class MyJdbcDAO implements MyDAO {

}

이제 MyService는 MyDAO라는 인터페이스에 대해 프로그래밍하는 구조로 바뀌었다. 이것의 장점은 MyDAO의 구현이 언제든지 교체 가능하다는 것이다. 구현한 알고리즘을 통째로 교환해 사용할 수 있게 하는 것이 전략패턴의 특징이다. DAO 구현이 필요에 따라 JDBC가 아닌 하이버네이트나 다른 종류의 퍼시스턴스여야 한다면 언제든지 MyDAO 인터페이스를 구현해 만들면 된다. MyService는 구현이 바뀌는 것에 전혀 영향 받지 않는다.
MyService의 로직이 복잡해 구현하면서 자주 테스트가 필요하다면 MyDAO 인터페이스를 구현한 간단한 테스트용 DAO 클래스를 만들어 MyService가 그것을 사용하도록 만든다. 이는 MyService와 MyDAO의 관계를 느슨하게 만들어 주었기 때문에 모두 가능한 것이다. 여기서 나온 MyService와 MyDAO는 아직 개선의 여지가 남아 있다. 하지만 일단 여기까지만 살펴보자. 
여기서 사용한 기법들은 모두 객체지향의 기본 설계원리와 패턴에 등장하는 것들이지 어떤 최신 기법들이 아니다. 물론 AOP라는 새로운 기술을 사용하지만, 그것이 추구하는 것은 또 다른 프로그래밍 모델이 아닌 OOP에 더 충실한 자바 코드를 만드는 데 도움을 주는 것일 뿐이다. 
앞에서 살펴본 것처럼 POJO 기반의 프레임워크를 가져다 사용하기만 했다고 해서 POJO 프로그래밍이 되고 그 유익을 누리는 것은 결코 아니다. POJO가 지향하는 자바의 객체지향적인 설계의 기본에 충실하도록 POJO 프레임워크의 도움을 받아 구현하는 것이 진정한 POJO 프로그래밍이다. 결과적으로 이렇게 만들어진 POJO 기반의 코드는 EJB나 그 이전의 자바개발 방법을 따라 만든 어떤 코드보다 더 간결하고 깔끔해진다. 이것이 객체지향 언어인 자바를 사용하면서 누려야 하는 진정한 혜택이 아닐까.

 

풍성한 도메인 모델

이제는 POJO 개발의 조금 다른 영역을 생각해 보자. POJO의 자바 오브젝트가 지닌 기본 특징은 하나의 오브젝트 안에 상태(State)와 행위(Behavior)를 모두 가지고 있는 것이다. 쉽게 말해 인스턴스 변수와 로직을 가진 메소드를 가지고 있다는 의미이다. 문제는 자바의 그런 특성이 EJB에 와서 이상한 오브젝트 형태로 왜곡된 것이다. 빈약한 오브젝트(anemic object)라고 불리는 것이 바로 그것으로, 로직이 없고 상태만 가진 오브젝트들이 다수 사용되었다. 그러면 그 로직에 해당하는 행위는 어디로 갔을까? 그것은 절차적인(procedural) 스타일로 작성된 서비스 레이어의 메소드로 들어갔다. 결과적으로 서비스 오브젝트는 과도한 로직이 트랜잭션 스크립트 형태로 반복되어 길게 등장하면서 갈수록 비대해졌고, 도메인 모델을 구현한 오브젝트는 빈약한 오브젝트로 오로지 상태 인스턴스 변수만 가진 전혀 객체지향 언어 답지 않은 결과만 남게 되었다. 
이러한 스타일은 EJB뿐만 아니라 그 이후에 등장한 POJO 기반의 프로그래밍에서도 쉽게 찾아볼 수 있다. <리스트 4>와 <리스트 5>는 각각 은행의 계좌를 이체하는 서비스의 메소드와 계좌를 구현한 도메인 모델이다.

<리스트 4> 계좌이체 서비스 클래스

public class MoneyTransferServiceProceduralImpl implements MoneyTransferService {
     private AccountDAO accountDAO;
     private BankingTransactionDAO bankingTransactionDAO;

public BankingTransaction transfer(String fromAccountId, String toAccountId, double amount) {
      Account fromAccount = accountDAO.findAccount(fromAccountId);
      Account toAccount = accountDAO.findAccount(toAccountId);
              assert amount > 0;
             double newBalance = fromAccount.getBalance() - amount;
             switch (fromAccount.getOverdraftPolicy()) {
             case Account.NEVER:
               if (newBalance < 0)
                 throw new MoneyTransferException("In sufficient funds");
     break;
     case Account.ALLOWED:
       Calendar then = Calendar.getInstance();
       then.setTime(fromAccount.getDateOpened());
       Calendar now = Calendar.getInstance();
       double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR);
         int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH);
         if (monthsOpened < 0) {
         yearsOpened--;
         monthsOpened += 12;
      }
      yearsOpened = yearsOpened + (monthsOpened / 12.0);
      if (yearsOpened < fromAccount.getRequiredYearsOpen() ||        newBalance < fromAccount.getLimit())
throw new MoneyTransferException("Limit exceeded");
break;
default:
        throw new MoneyTransferException("Unknown overdraft type: " + fromAccount.getOverdraftPolicy());
}
     fromAccount.setBalance(newBalance);
     toAccount.setBalance(toAccount.getBalance() + amount);
     TransferTransaction txn = new TransferTransaction(fromAccount, toAccount, amount, new Date());
      bankingTransactionDAO.addTransaction(txn);
      return txn;
    }
}


 

<리스트 5> Account 도메인 클래스

public class Account {
      public static final int NEVER = 1;
      public static final int ALLOWED = 2;

      private int id;
      private double balance;
      private int overdraftPoicy;
      private String accountId;
      private Date dateOpened;
      private double requiredYearsOpen;
      private double limit;
      // getters/setters
}

 

MoneyTransferServiceProceduralImpl의 transfer 메소드는 길고 복잡하다. 자세히 살펴보면 사실 Account라는 오브젝트에 속해야 하는 로직들이 이체서비스의 서비스 로직에 빠져나와 있음을 알 수 있다. 반면에 Account 오브젝트에는 행위(메소드)는 없고 상태(필드)만 남아 있다. 만일 여기서 사용된 Account에 마땅히 들어가야 할 내용이 다른 곳에서 또 필요하다면? 그때는 복잡한 로직 코드가 여기저기 중복될 수밖에 없다. 
그럼 객체지향 기술의 장점을 충분히 누릴 수 있도록 이 코드를 POJO답게 수정해 보자. 가장 간단한 방법은 Account 오브젝트가 가지고 있어야 하는 행위를 Account로 옮기는 것이다. <리스트 6>과 <리스트 7>은 각각의 코드를 수정한 것이다.

<리스트 6> 수정된 계좌이체 서비스 클래스

public class MoneyTransferServiceProceduralImpl implements MoneyTransferService {
    …
     public BankingTransaction transfer(String fromAccountId, String toAccountId, double amount) {
       Account fromAccount = accountDAO.findAccount(fromAccountId);
       Account toAccount = accountDAO.findAccount(toAccountId);
assert amount > 0;

        fromAccount.debit(amount);
        toAccount.credit(amount);

        TransferTransaction txn = new TransferTransaction(fromAccount, toAccount, amount, new Date());
         bankingTransactionDAO.addTransaction(txn);
         return txn;
}
}


 

<리스트 7> 수정된 Account 오브젝트

class Account {
      // fields
     // getters/setters
     …
public void debit(Account fromAccount, double amount) {
     double newBalance = getBalance() ? amount;
     switch (getOverdraftPolicy()) {
         ... 
    }
     setBalance(newBalance);
}

public void credit(Account toAccount, double amount) { 
    setBalance(getBalance() + amount);
  }
}

이체서비스 오브젝트 안의 한 메소드에 지저분하게 들어 있던 이체 로직은 그 로직이 있어야 할 Account 안에 절절한 메소드 형태로 옮겨졌다. 서비스 메소드에서는 그 오브젝트의 메소드를 호출해 서비스 로직을 수행하는 간단하고 명확한 코드로 역시 변경되었다. 이제 Account 오브젝트는 여러 로직과 계층에서 자신의 로직을 분산해 복사할 것 없이, 오브젝트 그대로 재활용되어 사용되는 객체지향의 혜택을 누릴 것이다. 또한 POJO이므로 Account와 MoneyTransferServiceProceduralImpl 모두 쉽게 테스트할 수 있다. 이렇게 객체지향 원리에 충실하게 도메인 모델을 만드는 것을 풍성한 도메인 모델(Rich Domain Model)이라고 한다.

 

진정한 POJO 프로그래밍 추구하기

이 글의 주제는 다이어트 POJO 프로그래밍이다. 필자처럼 체중이 많이 나가는 사람에게 다이어트는 매우 중요한 도전이자 과제이다. 다이어트가 왜 중요한가? 단지 체중을 줄여 날씬한 몸매를 만드는 것이 목적일까? 
그렇지 않다. 다이어트가 중요한 이유는 그것이 건강을 추구하기 때문이다. 다이어트를 통해 궁극적으로 얻고자 하는 것은 건강이다. 마찬가지로 POJO를 잘 사용하면 군더더기 없는 최소한의 코드로 이전과 동일한 결과를 낼 수 있지만, 더 중요한 의미는 더 건강한 코드를 만드는 데 있다.
단지 어느 순간에 상태가 좋다고 해서 건강하다고 할 수는 없다. 건강이란 외부의 스트레스와 변화에도 흔들리지 않고 견고하게 버틸 수 있는 힘인데, 이렇게 건강한 코드를 만들기 위해서는 반드시 자동화된 테스트 코드를 개발해야 한다. 잘 만들어진 테스트 코드는 지속적인 변화에 유연하게 대응할 수 있도록 도와준다. 변화를 두려워하지 않게 만들고 코드의 구조를 개선하기 위한 리팩토링도 안심하고 진행할 수 있게 지원한다. 또한 POJO로 잘 설계된 코드는 테스트 코드를 쉽게 만들 수 있도록 해준다. 이런 선순환이 지속되면 POJO 프로그래밍은 더 성숙된 결과로 나아가게 될 것이다. 그래서 필자는 POJO 프로그래밍의 꽃은 테스트 코드 작성이라고 생각한다. 
2005년에 프랑스의 온라인 세무시스템은 큰 변화를 겪었다. 기존에 EJB와 J2EE 기반으로 구현된 기존 시스템을 스프링과 하이버네이트를 사용하는 POJO 방식으로 전환한 것이다. 단 3개월 만에 시스템의 구조를 변환하면서 동시에 50개의 새로운 유즈케이스와 100개의 새로운 화면, 150개의 기존 화면을 전환시켰다. 
그 결과는 매우 성공적이었다. 손쉽게 작성할 수 있는 테스트와 간단한 패키징, 배포작업이 용이해졌고 지저분한 템플릿 코드를 제거하면서 생산성이 극대화되었다. 또한 기술적인 리스크가 줄고 일관성 유지가 쉬워졌으며 풍성한 도메인 모델을 적용하고 모든 레이어에 걸처 테스트를 작성하게 되어 큰 폭의 품질 향상이 이뤄졌다.
EJB나 무거운 기존 기술의 굴레에서 벗어나 객체지향 기술의 혜택을 가득 누릴 수 있는 즐거운 POJO 프로그래밍에 한번 도전해 보자. 혹시 지금 POJO 프레임워크를 사용해 개발하고 있다면 과연 자신이 만든 코드가 POJO의 원칙에 맞게 작성되었는지 살펴보자. 그리고 마지막에는 반드시 테스트를 작성하라. 그것이 POJO를 POJO답게 쓰게 하고 그 가치를 누리도록 도와줄 것이다.

 
출처 : http://cafe.daum.net/playtrade/9l2D/9


JDBC란? Java 스크랩

JDBC 란?
  - Java에서 Database관련 작업을 담당하는 Package.

JDBC의 특징
  - 별도의 install 과정이 불필요.
  - DB와의 연결은 Strring 형태의 URL에 의해서 수행.
  - String 형태로 표준 SQL문을 전달.
  - JDBC는 Spec으로 제공되며, 실재 Code는 각 Database Vender에 의해 작성되고 제공된다. 
    * Sun은 오직 interface로서 모든 Database에 공통으로 사용될 수 있는 작업 형식을 지정할 뿐이다. 
      > Sun의 JDBC Spec
        - Core API : java.sql package
                      Client side application 개발용 라이브러리
          =>DriverManager
          =>Driver
          =>Connection, Statement, ResultSet
          =>DatabaseMetaData, ResultSetMetaData
        - Extension API : javax.sql package(JDBC 2.0에 추가된 Package)
                             Server side application 개발용 라이브러리
          =>DataSource
          =>RowSet
    * Oracle은 classes111.zip과 classes12.zip 두가지 package를 제공하고 있으며 각각 Version에
       서로 달리 사용된다.
       일반적으로 JDBC1.0만을 사용할 때는 classes111.zip을 사용하고 JDBC2.0과 함께 사용할 때는 
       classes12.zip을 사용한다.
       (ORA_HOME/jdbc/lib)
  - MetaData(Result 타입의 확인,Stored Procedure 제거) 사용 가능

JDBC의 장점
  - JDBC를 이용하는 경우 interface기반으로 구축되기 때문에 어느 Database를 사용하더라도 동일한 코드를 
    작성할 수 있고 사용 중 Database를 교체하더라도 Code를 수정 작업은 거의 존재하지 않는다.

JDBC의 구분
  * Version 구분
    - JDBC는 현재 1.x와 2.0 Version으로 구분된다. 1.x version은 기본 기능만을 포함하고 있으며 가장 
       대표적인 특징은 Query의 결과를 순차적으로 한번만 사용할 수 있고 Database와 단절된 상태로만 
       사용한다는 점이다. 이에 비해 2.0의 경우에는 Query의 결과를 Random Access방식으로 
       사용할 수 있고 직접 Database와 연결된 상태로 사용하므로 결과를 수정하므로서 Server의 Data에 
       대한 Delete, Update, Insert작업을 직접 수행할 수 있다.

  * Version별 장 단점.
    - 1.x의 장점 : Database와 연결을 지속적으로 유지할 필요가 없으므로 매우 가볍게 사용할 수 있고,
                        많은 Data를 처리하더라도 순차적으로 접근 후 1번만 사용하므로 Memory에 계속 
                        Load할 필요가 없어,작은 Memory 만으로도 작업을 수행할 수 있다.( : 2.0의 단점)
    - 2.0의 장점 : Random Access가 가능하므로 Query결과를 자유롭게 사용할 수 있고,
                        Update, Insert, Delete작업을 직접 수행할 수 있으므로 관리가 편리하다.
 
* 장 단점을 고려한 사용 방법
    만일 많은 Data를 읽기 전용으로 사용할 경우에는 1.x이 훨씬 유용한 방법으로 채택될 수 있다.
    만일 소수의 Data를 빈번하게 읽고 갱신할 필요가 있다면 2.0이 훨씬 유용한 방법으로 채택될 수 있다.
  * JDBC Driver의 종류 : 4가지 Type으로 구분한다.

    - Type I : JDBC-ODBC Bridge driver
                  JDBC로 Database에 직접 연결하지 않고 ODBC를 통해서 작업하는 방법.
                  장점 : Windows환경을 재사용할 수 있다.
                  단점 : Windows상에서 ODBC를 설정해 주어야 한다. 속도가 가장 느리다.
    - Type II : Native API party-Java driver (OCI)
                   JDBC명령을 각각의 Database client program에 적합하게 변환하는 방법.
                   장점 : 속도가 가장 빠르다.
                   단점 : Database Client를 설치해야 한다.
    - Type III : JDBC-Net pure Java driver
                   Database에 종속되지 않은 Protocol로 JDBC를 번역 후 직접 연결 처리.
    - Type IV : Native-protocol pure Java driver(THIN)
                    DB업체에서 지원하는 JDBC Driver로 JDBC문장을 개별 Protocol로 변환.
                    장점 : Client에 대한 어떠한 추가작업도 필요하지 않다.
                    단점 : OCI보다 속도가 느리다.
    - 주로 작업은 OCI와 THIN을 이용.

 

  * JDBC 작업을 위한 준비.
    - Oracle을 설치하고 classes12.zip 파일을 자신의 Computer에 복사 후 CLASSPATH에 등록한다.

  * JDBC의 기본 작업 절차.
    - Database에 연결.
    - Query전송.
    - 결과를 이용한 작업 처리.
    - 닫기.

  * Database에 연결 작업 처리.
    - Database에 연결하기 위해서는 다시 아래와 같은 과정이 필요.
   - Driver 등록 : Database에 연결.
      > Driver등록 : Driver등록은 자신이 사용할 Database Vender의 Driver를 java.sql package에 
        연결시키는 작업 과정이다.

      > 이 과정에서 자신이 사용할 Type을 1차 지정하게 된다.
      > Type I(JDBC-ODBC Bridge방식)
        - Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
      > Oracle제품 사용의 경우.
       - 방법 I : Class.forName("oracle.jdbc.driver.OracleDriver");
                     classes12.zip에는 Oracle JDBC작업을 수행하기 위한 각종 class들이 포함되어 있고 
                     그 중 한가지가 oracle.jdbc.driver.OracleDriver이다.
                     Driver가 하는 역할은 java.sql package의 interface들과 oracle이 제공하는 class들을
                    연결시키는 작업을 수행한다.
                    이 작업은 아래와 같이 다양한 표현식으로 사용 가능한다.
        - 방법 II : Class.forName("oracle.jdbc.driver.OracleDriver").newInstance()
        - 방법 III : 
                     .... oraDrv = new oracle.jdbc.driver.OracleDriver()
                     DriverManager.registerDriver(oraDrv);
      > DB연결 작업
        - 앞서 등록 과정에서는 DriverManager에 자신이 사용할 DB package를 연결시켰으므로 
          이 과정에서 DriverManager를 통해 연결 작업을 수행하게 된다.
        - 연결 작업을 수행할 때 Oracle의 경우에는 2차 Type결정 과정을 포함한다.
        - 연결 객체는 java.sql.Connection으로 제공.
      > 다양한 연결 방법.
        - JDBC-ODBC Bridge를 사용할 경우.(미리 ODBC Data Source는 존재.)
          =>Connection con = DriverManager.getConnection("jdbc:odbc:DSName","user","pw")
        - THIN/OCI 방식을 사용하는 경우.
          =>Connection con = DriverManager.getConnection("url","user","pw")
        - url의 구성.
          =>mainprotocol:subprotocol:type:연결정보
          =>main protocol : jdbc(고정)
          =>sub protocol : oracle (Oracle 고정)
          =>type : oci8(oracle 8.x), oci7(oracle 7.x), thin
          =>연결정보 : oci - tns, thin - host:port:sid
        - 연결예.
          =>Connection con = DriverManager.getConnection("jdbc:oracle:oci8:@COLEE","scott","tiger");
          =>Connection con = DriverManager.getConnection
           "jdbc:oracle:thin:@localhost:1521:tt","scott","tiger");

  * Query 전송 작업 : Statement 생성 -> Query 전송.
    - Statement 생성 작업 : 적용할 JDBC Version도 함께 설정. - 기본은 1.x
      > Statement의 종류.
        - default : Statement - 일반적인 Query를 직접 전송하기 위해 사용하는 Statement.
        - PreparedStatement - Parameter를 통해 미리 지정된 위치에 값을 나중에 등록하는 Statement
        - CallableStatement - Function, Procedure, Package를 호출하기 위해 사용하는 Statement.

        - Statement생성하기.
          =>Statement stmt = con.createStatement();  => 1.x 생성
          =>Statement stmt = con.createStatement(int , int); => 2.0생성.
            >> params : 순차적혹은 Scroll가능형태, 읽기전용혹은 쓰기 가능.
            >> 상수는 ResultSet interface에 정의되어 있음.

--------------------------------------------------------------------------------------------------|                                    상  수                             |                             의  미                                 |
--------------------------------------------------------------------------------------------------
|  CONCUR_READ_ONLY                                       |  읽기 전용 작업 처리 : 1.x                                  |
--------------------------------------------------------------------------------------------------
|  CONCUR_UPDATABLE                                       |  Query결과로 Update지원 : 2.0                           |
--------------------------------------------------------------------------------------------------
|  TYPE_FORWARD_ONLY                                      |   순차적 접근 : 1.x                                           |
--------------------------------------------------------------------------------------------------
|  TYPE_SCROLL_INSENSITIVE                               |   Random Access : DB변경 적용X                    |
--------------------------------------------------------------------------------------------------
|  TYPE_SCROLL_SENSITIVE                                  |   Random Access : DB변경 적용O                    |
--------------------------------------------------------------------------------------------------
           

       >> 1.x  :  CONCUR_READ_ONLY + TYPE_FORWARD_ONLY
 
       - Prepared Statement 생성.
          =>PreparedStatement stmt = con.prepareStatement(String sql);
          =>PreparedStatement stmt = con.prepareStatement(String qry, int, int);
          =>prepared statment는 미리 자신이 사용할 Query를 등록하는 방법을 사용한다.
              params로 사용되는 두개의 int는 Statement와 동일하다.
        - Callable Statement
          =>CallableStatement stmt = con.prepareCall(String qry);
          =>CallableStatement stmt = con.prepareCall(String qry, int, int);
          =>callable statement는 prepared statment와 동일한 방법 사용.
        - PreparedStatement&CallableStatement qry작성방법.
          =>qry작성시 사용자 입력 항목은 ? 로 처리 : Data Type 구분하지 않음.
          =>값 설정시에는 index로 지정하며 1부터 시작.(모든 JDBC는 1부터시작)
          =>Data Type에 따라 각각의 Statement에서는 setXXX(int , value)지원.
          =>예) PreparedStatement stmt = con.prepareCall("Select * From ?"); 
                   stmt.setString(1,"tabs");
                  - NULL 표현을 위해서는 setNull(index, type) : Type은 java.sql.Type의 상수

        - CallableStatement는 "{ call PROC(?,?)}" 로 query문 지정.
          =>parameter설정은 PreparedStatement와 동일.
          =>function의 return 및 parameter의 registerOutParameter(index, paramType) method로 미리 등록.
          =>execute후 결과 확인은 getXXX(index)로 각각 등록한 OutParameter를 읽어 들일 수 있다.
        - Query수행하기.
          =>executeUpdate, executeQuery, execute로 수행. - 세가지 모두 적용.
          =>executeUpdate : Insert, Delete, Update, Drop, Create, Alter문 처리.
                                     갱신 Row수 return.
          =>executeQuery : Select만 처리.
          =>execute : Type명확하지 않을 경우 처리. return이 true이면 ResultSet, false이면 update수. 

                            -> stmt.getUpdateCound(), stmt.getResultSet()


  * 결과 처리하기
    - Select 문의 경우에는 ResultSet으로 결과를 구해서 활용할 수 있다.
    - ResultSet을 활용하는 방법은 1.x을 기반으로 2.0에 추가적인 기능이 더해진다.
    - 1.x 활용 방법.
      > 기본 구조는 순차적인 형태로서 Enumeration과 비슷한다.
      > ResultSet rs = stmt.executeQuery();
         while(rs.next())
         {
           String name = rs.getString(1);
           int age = rs.getInt(2);
           Timestamp birth = rs.getTimestamp(3);
         }
      > 순차적인 검색만 가능하므로 한번 next되어 넘어간 record를 다시 사용할 수 없다.
      > 날짜는 Date Type을 사용하고 시간은 Timestamp를 사용한다.
      > 사용하는 Data Type은 java.sql package에 정의되어 있다.
      > Data의 value가 NULL일 경우에는 직접 확인할 수 없고 field를 읽어 들인 후 rs.wasNull() method를 
        호출하므로서 알 수 있다.
    - 2.0 활용 방법 : 검색.
      > boolean beforeFirst() : 첫 레코드 이전의 시작위치로 이동.
      > boolean afterLast() : 마지막 레코드 다음의 끝위치로 이동.
      > boolean first() : 첫 레코드로 이동.
      > boolean last() : 마지막 레코드로 이동.
      > boolean isBeforeFirst, isAfterLast, isFirst, isLast : 현재위치가 지정된 위치인가 확인.
      > boolean absolute(int row) : 지정된 레코드로 이동.
      > boolean next() : 다음 레코드로 이동.
      > boolean previous() : 이전 레코드로 이동.
      > boolean relative(int) : 현재위치로부터 상대적인 레코드 위치로 이동.

    - 2.0 활용 방법 : 데이타 갱신.
      > Delete : void deleteRow()
      > Update : update할 Row로 이동 후
                     rs.updateString("NAME","COLEE");
                     rs.updateRow();  or rs.cancelRowUpdates();
      > Insert : 아무 위치에서나.
                   rs.moveToInsertRow();
                   rs.updateString(1,"COLEE");
                   rs.updateInt(2,5);
                   rs.insertRow();
                   rs.moveToCurrentRow();

  * 닫기 작업.
    - 작업이 종료되면 반드시 ResultSet -> Statement -> Connection순서로 close()를 
     호출해 주어야 한다.

  * 각종 부가 정보 활용하기.
      > 부가 정보는 MetaData라는 이름으로 제공된다.
      > DatabaseMetaData interface : Database에 관련된 정보를 제공
        - Connection으로부터 getMetaData()를 호출해서 구할 수 있다.
        - Connection에 사용된 각종 정보 제공.
        - Schema 리스트 제공.
        - 지정 Schema로부터 접근 가능한 Table, View등 제공.
      > ResultSetMetaData interface : ResultSet에 관련된 정보 제공.
        - ResultSet으로부터 getMetaData()를 호출해서 구할 수 있다.
        - ResultSet의 Column수 Column Name 및 Data Type 정보
        - 소속 Schema Name.
        - 현재 ResultSet의 상태 : 갱신 가능 여부등.

  * Transaction관리.
    - Transaction은 Connection으로 관리한다.
    - 기본은 Auto Commit형으로 close하면 자동으로 수행한 결과를 Commit한다.
    - 만일 Default인 Auto Commit을 사용하지 않고 직접 Transaction을 관리하고자 할 경우에는 
       Connection객체로부터 setAutoCommit(false)를 호출하고 적절한 위치에서 
       commit(), rollback()을 호출해 준다.

    - Connection con = null;
       Statement con = null;
       try {
         con = getConnection();

         con.setAutoCommit(false);
         stmt = con.createStatement();

         stmt.executeUpdate("delete from test where no = '1'");
         stmt.executeUpdate("delete from test where no = '2'");

         con.commit();
         con.setAutoCommit(true);
      } catch(SQLException e) {
        con.rollback();
        System.out.println(e.getMessage());
      } fanalliy {
        if (stmt != null) stmt.close();
        if (con != null) con.close();
      }
 
  * 기타.
    - 대부분의 Database관련 작업은 SQLException을 처리해 주어야 한다.
    - 이상의 내용은 JDBC Spec에 따른 사항이고 Oracle은 고유의 기능들(Simple Connection Pool등)을 
      함께 제공한다.
    - 직접 JDBC를 이용하는 방법이외에도 보다 친숙한 형태로 사용하도록 하는 SQLJ를 이용하는 방법도 
      존재한다.



출처 - http://cafe.naver.com/hermeswing/121


Framework : iBatis Java



* iBatis



- iBatis의 장점
 1) 필요없는 코드를 줄이고 쿼리 구문만을 사용하기 때문에 코드의 양을 다른 DB Connection 방법보다 
    간단하고 생산성이 높다.
 2) Connection 관련된 것은 sqlMapConfig.xml에 작성하고, 모든 쿼리는 sqlMap.xml에 작성하고, 
    결과 값은 Mapping된 자바빈즈(vo)에 주입하기 때문에 작업의 분배가 가능하다.
 3) 어느 프로그래밍 언어로도 구현이 가능하다.(이식성이 높다)

- iBatis의 단점 : xml를 파서하여 사용하기 때문에 직접 쿼리를 사용하는 것보다 수행시간이 오래 걸린다.


1. DaoService :  사용자의 요청을 인식하고 DAO 객체를 선별한다.
2. dao.xml : 설정 정보와 DAO 구현체들을 묶어주는 역할을 하고, SqlMapConfig.xml에 설정된
                 트랜잭션 매니저에게 위임
3. SqlMapConfig.xml : 트랜젝션을 관리하고, sqlMap의 결과 값을 읽어들임
4. SqlMap.xml : 구문을 실행하여 DBMS에서 가져온 결과 값을 자바빈즈(vo)에 실행된 결과를
                      Mapping한다,


-SqlMapConfig.xml

<!DOCTYPE sqlMapConfig PUBLIC '-//ibatis.apache.org/DTD SQL Map Config 2.0//EN'
'http://ibatis.apache.org/dtd/sql-map-config-2.dtd'>
<sqlMapConfig>
    <!-- Connection 획득 -->
    <transactionManager type="JDBC">
        <dataSource type="simple">
            <property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver" />
            <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:DB 리스너명" />
            <property name="JDBC.Username" value="DB ID" />
            <property name="JDBC.Password" value="DB Password" />
        </dataSource>
    </transactionManager>
    <!-- sqlMap 설정 -->
    <sqlMap resource="ex2/map/sqlMap.xml"/>
</sqlMapConfig>


- SqlMap.xml

<!DOCTYPE sqlMap PUBLIC '-//ibatis.apache.org/DTD Sql Map 2.0//EN'
'http://ibatis.apache.org/dtd/sql-map-2.dtd'>
<sqlMap>
    <!-- 별칭을 사용한다. -->
    <typeAlias alias="vo" type="ex2.vo.SawonVo" />
    <insert id="ins" parameterClass="vo">
        insert into sawon
        values (sawon_seq.nextVal,#saname#,#deptno#,#sajob#,#sapay#,sysdate,#sasex#,#samgr#,#comm#)
    </insert>
    <select id = "sawonAll" resultClass="vo">
        select * from sawon
    </select>
</sqlMap>


1 2