티스토리 뷰

Framework/iBatis

iBatis

미련곰 2009. 7. 6. 11:38
iBatis 사용시 XML상의 reference 관련 error시

이클립스에서 느낌표가 나오면 왠지 모르게 짜증이 난다

error.png

[기존]

  1. <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

[수정]

  1. <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

주소가 수정되었나보다. 브라우저에서 주소창에 치면 이전 것도 다운로드 되는데 이클립스에서는 왜 안되지?

다른 sql-map, dao도 올려놓자

  1. <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
    <!DOCTYPE dao PUBLIC "-//ibatis.apache.org//DTD DAO Configuration 2.0//EN" "http://ibatis.apache.org/dtd/dao-2.dtd">

아놔~ 그 문제인줄 알았는데,

회사에서는 외부 인터넷에 연결하기 위해서 프록시 서버를 연결해야 하는데 이클립스에 세팅을 해줘야 하기 때문이었다.

네트워크 연결이 안되니 dtd 파일을 다운받을 수 없고 xml validation도 할 수 없는 것이 었다.

conn.png

 

 iBATIS in Action
(쉽고 강력한 SQL 매핑 프레임워크 아이바티스)

위 책의 필요한 사전 배경지식: Java, JDBC(매핑+), SQL, XML

외부 링크 : 아이바티스 커뮤니티(http://ibatis.apache.org)

SVN : Subversion Source Control

JIRA: for 이슈 트래킹(아틀라시안)

Confluence : wiki 문서 작성

 소스 코드 : 매닝 출판사 웹 사이트(www.manning.com/begin)
                 위키북스 오픈소스 & 웹 시리즈 에디터 일래스틱 온라인(http://web2.0business.or.kr/)

 

  • 머리말

    • 프레임워크 - 사전적 의미(뼈대, 틀, 골자)
    • 향상 : 가독성, 유지보수성, 생산성
    • 퍼시스턴스 계층에 적용할 프레임워크

      • 아이바티스 - JDBC
      • 객체 관계 매핑 툴(ORM) -  하이버네이트 / TopLink
    •  iBATIS : 더 빠른 JDBC 코딩을 위한 일반화된 프레임워크

      • SQL 매퍼 + DAO 프레임워크

 

 요약 (iBATIS)

  • SQL 매핑으로 객체를 관계형 데이터베이스에 저장
  • 애플리케이션이 퍼시스턴스 계층에 일관성있게 접근하는 것을 도와줌
  • 전사적인 수준의 퍼스스턴스 계층에 보다 적함(소규모 시스템에 비교하여)
  • 특징

    • 간단함 - 간단한 퍼시스턴스 프레임워크
    • 생산성 - 62%정도 줄어드는 코드(JDBC와 비교하여), 간단한 설정(근거: 이탈리안 자바 사용자 그룹의 연구)
    • 성능 - 구조적 강점(데이터 접근 속도 높여주는 JOIN매핑)

      • 여러가지 방식의 데이터 가져오기 전략(가져오기 미루기, SQL 줄이기 기법)
    • 관심사의 분리 - 설계를 향상(차후 유지보수성 위해)

      • 리소스를 관리하여 계층화를 지원(커넥션, PreparedStatement, 결과셋)
    • 작업의 분배 - 팀을 세분화하는 것을 도움

      • SQL 문이 애플리케이션 소스 코드로부터 완전히 분리
    • 이식성 - 어떤 프로그래밍언어로도 구현 가능

      • 예) 자바, C#(iBATIS.NET), Ruby(RBATIS)
    • 오픈소스 - 무료+ 커뮤니티티
  • 언제 사용하지 말아야 하나?

    • 개발자가 모든 것에 대해 영원한 결정권 소유

      • 애플리케이션 설계와 데이터베이스 설계에 대한 모든 결정권 보유
      • iBATIS는 관계형 데이터베이스를 위해 설계
      • => 관계 매핑 솔루션(ORM;하이버네이트..) 사용 - 설계시 이점, 생산성 향상
        예) JIRA(이슈 트래킹 패키지 소프트웨어 제품)
    • 완전히 동적인 SQL을 요구시

      • 애플리케이션의 핵심 기능 : SQL을 동적으로 생성일 경우
      • iBATIS의 사용이유: 수작업 SQL 구문 작성, 관리
      • 애플리케이션 -> 대부분의 SQL 구문이 SQL 자동 생성 클래스 로부터 동적으로 생성시 위의 장점은 무의미
    • 비 관계형 데이터베이스 사용

      • 파일, 엑셀, XML
      • => 순수한 JDBC, 저수준 파일 입출력 API 권장장
    • 요구사항과 상반되는 개발 방향, 설계지침 - 복잡도 증가, 프레임워크 자체의 역할 범위 넘어서는 것
  • (주로)관계형 데이터베이스를 위해 설계

    • 비-관계형 기술(일반적 파일, XML, 엑셀 스프레드 시트)사용시 타 API 이용이 효과적
  • 객체 관계 매퍼(ORM) - 애플리케이션~데이터베이스에 대한 결정권 보유
  • JDBC - 주로 동적으로 생성되는 SQL 코드로 작업하는 애플리케이션

 

x설치와 설정 (iBATIS)

  • 배포판 얻기

    1. 바이너리 배포판: 가장 빠르고 쉬운 방법

      • 컴파일된 상태 -> 다운받아 압축을 풀고 사용
    2. 소스로부터 빌드하기

      • 프레임워크를 확장, 버그 수정
      • 소스코드를 직접 컴파일 결과 확인시
    • 배포판의 구조

      • ibatis-2.3.0.677.png
      • 2.3.0.677에서는 jar 파일들(/lib 디렉토리내)가 ibatis-2.3.0.677.jar로 하나로 통합되었다.
      • /doc

        • user-javadoc.zip : for iBATIS 프레임워크를 사용해서 개발을 하는 사용자들
        • dev-javadoc.zip : for iBATIS 프로젝트의 모든 JavaDoc 문서를 포함하고 있는 파일
      • /lib

        • ibatis-common-2.jar : SQL Maps와 DAO 프레임워크 모두가 사용하는 공통 컴포넌트 포함
        • ibatis-sqlmap-2.jar : SQL Maps 프레임워크의 컴포넌트들을 포함하고 있는 파일
        • ibatis-dao-2.jar : DAO 프레임워크 컴포넌트들을 포함하고 있는 파일
      • /src

        • ibatis-src.zip : 프레임워크의 JAR파일을 빌드하는데 사용된 전체 소스를 포함하고 있는 파일
  • 애플리케이션에 iBATIS 붙이기

    • 클래스패스 추가(iBATIS 파일 경로 컴파일시, 실행시)

      • 단독 실행 애플리케이션

        • 클래스패스 옵션 추가

          1. java -cp ibatis-sqlmap-2.jar:ibatis-common-2.jar:. MyMainClass
      • 웹 애플리케이션

        • iBATIS의 jar 파일들을 WEB-INF/lib 디렉토리에 둔다
    • JRE 공유 디렉토리(lib/ext 디렉토리)에 올려서 사용가능하지만 가급적 피할 것

      1. 애플리케이션 변경되어 파일 수정시 공유하고 잇는 파일을 참조하는 모든 애플리케이션을 테스트 필요
      2. 클래스로더 문제((두 개의 서로 다른 클래스로더가 읽으면 서로 다른 클래스로 간주: 정적변수 공유 X)

 

  • SQL Maps 설정 파일

    • <SqlMapConfig.xml>

      1. <!SqlMapConfig.xml SQL Map configuration file-->

        <?xml version="1.0" encoding="UTF-8"?>
        <!-- 유효성 체크를 위한 DOCTYPE과 DTD를 적는다 -->
        <!DOCTYPE sql-map-config
            PUBLIC "-//iBATIS.com//DTD SQL Map Config 1.0//EN"
           "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
        <sql-map-config>
            <properties resource="db.properties" />
        <!-- 전체 설정 옵션 -->
            <settings
                useStatementNamespaces='false'
                cacheModelsEnabled='true'
                enhancementEnabled='true'
                lazyLoadingEnabled='true'
                maxRequests="32"
                maxSessions="10"
                maxTransactions="5"
                />
        <!-- 트랜잭션 매니저 -->
            <transactionManager type="JDBC" >
                <dataSource type="SIMPLE">
                    <property name="JDBC.Driver" value="${driver}"/>
                    <property name="JDBC.ConnectionURL" value="${url}"/>
                    <property name="JDBC.Username" value="${user}"/>
                    <property name="JDBC.Password" value="${pword}"/>
                </dataSource>
            </transactionManager>
        <!-- SQL Map을 기술 -->
            <sql-map resource="sqlMap.xml" />
         
        </sql-map-config>
    • <properties> 요소 - 외부에서 이름/값 쌍의 리스트를 제공

      • 장점 : 공통 설정 부분은 모두 한 곳에 두고 각 환경별로 다른 값들을 properties 파일에 독립 가능
      • 속성

        • resource - 클래스 패스상에 있는 리소스(or 파일)

          • 클래스 로더가 애플리케이션의 클래스패스에서 그 리소스를 찾으려는 시도 함
          • 소스(db.properties)

            • driver=oracle.jdbc.driver.OracleDriver
              url=jdbc:oracle:thin:@localhost:1521:orcl
              user=scott
              pword=tiger
        • url - URL, java.net.URL에 의해 처리
    • <setting> 요소

      • useStatementNamespaces - 매핑 구문이 적절한 이름을 가지고 있어야 iBATIS가 실행 가능하도록 하는 옵션, 값(true/false)
      • cacheModelsEnabled - 캐시(차후 참조 가정->메모리 계속 저장), 값(true/false)
      • enhancementEnabled - CGLIB(실행 시간에 코드를 생성하는 라이브러리)에 최적화된 클래스-> 적재 지연 성능 향상 여부 지정, 값(true/false)
      • lazyLoadingEnabled - 적재 지연(필요할 때만 정보를 읽어들이는 기술), 값(true/false)
      • maxRequests - SQL작업(입력/수정/삭제/저장 프로시저 호출)의 한번에 수행가능한 개수, 기본값: 512
      • maxSessions - 세션(스레드, 관련되어 있는 트랜잭션과 요청의 묶음에 대한 정보 추적 사용), 기본값: 128
      • maxTransactions - 데이터 트랜잭션의 개수, 기본값: 32
    • <typeAlias> 요소 - FQCN(완전한 형태의 클래스 이름, Fully Qualified Class Name) 대신 별칭을 붙임

      • 예)

        • <typeAlias alias="Account"
                type="org.apache.ibatis.jgamestore.domain.Account" />
      • 기본 내장 별칭들

        • 트랜잭션 매니저의 별칭

          • JDBC <- com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
          • JTA <- com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
          • EXTERNAL <- com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
        • 데이터 타입

          • string <- java.lang.String
          • byte <- java.lang.Byte
          • long <- java.lang.Long
          • short <- java.lang.Short
          • int <- java.lang.Integer
          • integer <- java.lang.Integer
          • double <- java.lang.Double
          • float <- java.lang.Float
          • boolean <- java.lang.Boolean
          • decimal <- java.math.BigDecimal
          • object <- java.lang.Object
          • map <- java.util.Map
          • hashmap <- java.util.HashMap
          • list <- java.util.List
          • arraylist <- java.util.ArrayList
          • collection <- java.util.Collection
          • iterator <- java.util.Iterator
        • 데이터 소스 팩토리 타입

          • SIMPLE <- com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory
          • DBCP <- com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory
          • JNDI <- com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory
        • 캐시 컨트롤러 타입

          • FIFO <- com.ibatis.sqlmap.engine.cache.fifo.FifoCacheController
          • LRU <- com.ibatis.sqlmap.engine.cache.Iru.LruCacheController
          • MEMORY <- com.ibatis.sqlmap.engine.cache.memory.MemoryCacheController
          • OSCACHE <- com.ibatis.sqlmap.engine.cache.OSCacheController
        • XML 결과 타입

          • Dom <- com.ibatis.sqlmap.engine.type.DomTypeMarker
          • domCollection <- com.ibatis.sqlmap.engine.type.DomCollectionTypeMarker
          • Xml <- com.ibatis.sqlmap.engine.type.XmlTypeMarker
          • XmlCollection <- com.ibatis.sqlmap.engine.type.XmlCollectionTypeMarker
    • <transactionManager> 요소

      • type - 어떤 트랜잭션 관리자르 사용할지 결정

        • JDBC : 간단한 JDBC 기반 트랜잭션 관리 기능 제공
        • JTA : 컨테이너 기반한 트랜잭션 관리 기능 제공
        • EXTERNAL : 트랜잭션 관리자를 제공하지 않고 iBATIS 대신 애플리케이션이 직접 트랜잭션을 관리한다고 가정
      • commitRequired - 커넥션을 닫기 전에 commit/rollback 제어시, 기본값: false
      • <property> 요소 - 각 트랜잭션 관리자 서로 다른 설정 옵션 가능
      • <dataSource> 요소 - javax.sql.DataSource 객체를 사용 -> 커넥션 풀 작업을 표준화
      • type 속성 - 어떤 클래스의 객체를 생성해서 데이터 소스 팩토리를 얻어올지를 정하는 속성

        • SIMPLE - 간단한 커넥션 풀을 내장한 데이터 소스를 설정하고자 할 때(JDBC 드라이버만 빼고 데이터 소스에 필요한 모든 것을 자체 내장)
        • DBCLP - Jakarta Commons Database Connection Pool 구현을 제공
        • JNDI - JNDI(Java Naming and Directory Interface)를 통해 할당된 컨테이너 기반의 데이터 소스를 공유하도록 사용
      • <typeHandler>

        • 타입 핸들러 이용: JDBC 데이터베이스 전용 데이터형 -> 애플리케이션의 데이터형 변환(번역기)
    • <sqlMap> 요소

      • resource - SQL Map 파일을 자바 클래스패스에 두고 리소스로서 참조
      • url - java.net.URL 클래스가 인식하는 임의의 URL 값 이용

 

  • SQL Map API

    • SqlMapClient 인터페이스

      • queryForObject() - 데이터베이스로부터 한 개의 레코드를 가져다가 자바 객체에 저장

        • Object queryForObject(String id, Object parameter) throws SQLException;

          • 디폴트 생성자를 가진 객체를 생성(보편적 방법)
          • 디폴트 생성자가 없으면 throws "런타임 예외"
        • Object queryForObject(String id, Object parameter, Object result) throws SQLException;

          • 반환하는 값으로 사용될 객체를 받음
          • 결과값 -> 파라미터의 형태로 객체에 지정
          • 생성자가 protected / 디폴트 생성자가 없어서 객체를 쉽게 생성할 수 없을 때 유용
      • queryForList() - 한 개 이상의 레코드를 가져와서 자바 객체의 List를 만드는 데 사용

        • List queryForList(String id, Object parameter) throws SQLException;

          • 매핑 구문이 반환하는 모든 객체를 반환
        • List queryForList(String id, Object parameter, int skip, int max) throws SQLException;

          • 전체 결과의 일부만을 반환
          • skip : 지정된 개수만큼 건너뛰고
          • max : 지정된 개수의 레코드만 반환
          • 2.3버전부터 비권장
      • queryForMap() - 데이터베이스로부터 한 개 혹은 그 이상의 레코드를 가져올 때 자바 객체의 Map을 반환

        • Map queryForMap(String id, Object parameter, String key) throws SQLException;

          • 퀴리 실행후 Map 객체를 생성하여 반환
          • key : 결과 객체를 가리키는 키, -> 지정된 프로퍼티의 값

            • Map accountMap = sqlMap.queryForMap(
                 "Account.getAll", null, "accountId");
              System.out.println(accountMap);
        • Map queryForMap(String id, Object parameter, String key, String value) throws SQLException;

          • 결과값 객체 -> value 파라미터에 지정된 프로퍼티 값이 됨

            • accountMap = sqlMap.queryForMap(
                 "Account.getAll", null, "accountId", "username");
              System.out.println(accountMap);
  • non-query 구문

    • 데이터 갱신

      • insert 메소드

        • Object inser(String id, Object parameterObject) throws SQLException;

          • 파라미터 : 실행할 매핑 구문의 이름, 파라미터 객체(데이터베이스에 데이터 삽입하는 데 사용)
          • 반환 : 객체
      • update 메소드

        • int update(String id, Object parameterObject) throws SQLException;

          • 파라미터: 실행할 매핑 구문의 이름, 값을 제공하는 데 사용할 파라미터 객체
          • 반환: update 구문에 의해 영향을 받은 레코드의 개수
      • delete 메소드

        • int delete(String id, Object parameterObject) throws SQLException;

          • 파라미터: 실행할 매핑 구문의 이름, 값을 제공하는 데 사용할 파라미터 객체
          • 반환: 삭제된 레코드의 개수
    • 매핑 구문

      • <insert> | id, parameterClass, parameterMap

        1. <parameterMap id="fullParameterMapExample" class="Account">
              <parameter property="accountId" jdbcType="NUMBER" />
              <parameter property="username" jdbcType="VARCHAR" />
              ...
          </parameterMap>

          <insert id="insertWithExternalInfo"
              parameterMap="fullParameterMapExample">
              insert into account (
                  account Id,
                  username, ...
              ) values (
                  ?, ? , ...
              )
          </insert>
        2. in Java 사용
          sqlMap.insert("Account.insertWithExternalInfo", account);
      • <update> | id, parameterClass, parameterMap
      • <delete> | id, parameterClass, parameterMap
      • <procedure> | id, parameterClass, resultClass, parameterMap, resultMap, xmlResultName
      • <sql> | id

        • 매핑 구문은 아니지만, 매핑 구문 내에서 사용될 수 있는 컴포넌트를 만들기 위해
      • <include> | refid

        • 매핑 구문은 아니지만, 매핑 구문에 <sql>타입으로 생성된 컴포넌트를 삽입하기 위해
  • iBATIS에서 XML 사용

    • XML 파라미터

      • <select id="getByXmlId" resultClass="Account" parameterClass="xml">
           ...
    • XML로 결과 생성

      • <select id="getByValueXml" resultClass=""xml" xmlResultName="account">
              ...

MVC 모델

  • Hierachy.png
  • 비지니스 객체 모델(도메인 클래스) : 처리할 도메인을 객체 지향적으로 묘사

    • 특정 비지니스 로직의 기능을 수행하기 위해 사용
    • 명사 -> 이름 -> 클래스
    • 약간의 로직 포함 가능(다른 계층에 접근하는 코드 금지)
    • 퍼시스턴스 계층의 메소드들의 파라미터의 반환값
  • 프리젠테이션 계층 : 출력(애플리케이션의 데이터/제어화면)하는 역할

    • 모든 정보의 레이아웃, 출력 형식을 정의
    • 예. HTML + JavaScript
    • 웹 애플리케이션

      • 장점: 플래폼에 독립적, 배포와 확장이 쉬움
      • 단점: 높은 수준의 사용자 제어 방식, 복잡한 데이터 처리 어려움

        • => 운영 시스템 위젯 사용하는 리치 클라이언트 방식(탭, 표, 트리, 내장 객체)
    • 리치 클라이언트 방식

      • 장점: 강력한 사용자 인터페이스
      • 단점: 배포의 어려움, 성능, 보안에 손이감
      • 예> Swing(자바), WinForms(.NET)
    • 복합적 리치 클라이언트(웹 애플리케이션 + 리치 클라이언트 방식)

      • 웹 서비스 <= 겉 모양, 비지니스 기능
      • XML <= 리치 클라이언트와 서버 간의 매개체
      • 단점: 애플리케이션의 개발과 배치에 더 많은 소프트웨어 필요

        • 예) Flex(매크로미디어), Flash 브라우저 플러그인(Laszlo시스템), Ajax(Asynchoronous JavaScript And XML)
  • 비지니스 로직 계층(서비스 클래스) - 애플리케이션이 제공하는 포괄적인 서비스들을 표현

    • 큰 덩어리 비지니스 기능을 관련된 비지니스 객체 모델에서 분리
    • 명사-동사 분리(예. 계좌(도메인) 메소드 분리 -> 은행서비스(비지니스 로직-계좌를 개설하다)
    • 서비스를 열어준다는 것은 클래스의 메소드를 사용할 수 있게 권한을 부여한다는 의미가 될 수 있음
  • 퍼시스턴스 계층 - 객체에 저장된 데이터(저장소, 객체 가져오기)

    • 데이터 저장 방식은 다양(관계형 데이터베이스 스스템, 쉼표로 분리된 텍스트, XML 등)
    • 추상화 필요 - 세부사항(데이터가 어떻게 저장/전송) 숨김
    • 내부 계층

      • 추상 계층 : 퍼스스턴스 계층에 일관성 있고 의미 있는 인터페이스 제공

        • 클래스와 메소드의 집합
        • 세부 구현 사항은 감싸서 꾸며줌
        • 적절히 추상 계층 구현을 도와주는 패턴 존재 : 예) 데이터 접근 객체(DAO;Data Access Object)
      • 퍼시스턴스 프레임워크 : 드라이버(or 인터페이스)와 소통하는 책임

        • 데이터 저장/가져옴/수정/검색/관리 메소드들 제공
        • 기반 저장소 클래스에 종속적
        • 표준API - 반복적이고 부차적인 코드가 필요

          • JDBC(자바 애플리케이션 -데이터베이스에 접근~표준 프레임워크)
          • ADO.NET(.NET 애플리케이션을 위한 표준 데이터베이스 퍼시스턴스 프레임워크)
      • 드라이버 / 인터페이스

        • 기반 저장소는 종류 다양(구현, 규모, 행동 상이) -> 소프트웨어 드라이버 사용
        • 드라이버와 통신하여 차이점들을 최소화 간소화하는 역할

 

데이터베이스

  • 관계형 데이터베이스의 사용 이유? - 무결성, 성능, 보안

    • 무결성 - 데이터의 일관성, 신뢰, 값의 정확성 보장

      • VARCHAR(25) NOT NULL
      • 데이터 타입 엄격히 준수 - 예) 값이 문자열 데이터, 길이가 25이하
      • 제약조건 엄수 - 예) UNIQUE
      • 트랜잭션 사용 - 연관(관련)된 데이터들의 일관성 있는 수정 방식(여러 사용자)
    • 성능 - 설계, 소프트웨어 튜닝, 하드웨어

      • 설계: 최고 중요!!!
      • 튜닝 고려사항: 캐시, 파일 관리자, 인덱스 알고리즘, 운영체제 등
      • 하드웨어 고려사항: 고속 디스크 어레이, 고속I/O 컨트롤러, 고속 하드웨어 캐시, 네트워크 인터페이스
    • 보안 - 기밀 데이터 유지
  • 데이터베이스 형태(4가지)

    • 애플리케이션 데이터베이스 - 작고 단순한 형태, 외부 영향 적음

      • 해당 프로젝트의 일보로 애플리케이션과 나란히 설계/구현
      • 예) 웹 애프리케이션 -> 데이터베이스(MySQL,PostgreSQL) -> 리포팅 툴(크리스탈 리포트)
    • 기업용 데이터베이스 - 큰 규모, 외부의 영향 큼

      • 통합 데이터베이스 - 트랜잭션처리 데이터베이스 - 리포팅 데이터베이스
    • 독점적 데이터베이스 - 직접 제작 vs 구입(패키지 소프트웨어)
    • 레거시 데이터베이스 - 오래된 데이터베이스(보잡성, 뒤죽박죽 설계, 의존성. age)

      • 수년간에 걸친 수정, 긴급한 수리 작업, 오류 은폐작업, 오류 피해가기, 땜질식 문제 해결, 기술적 제약 극복 패치..

 

iBATIS

  • iBATIS - 데이터 매퍼

    • 매퍼계층: 객체와 데이터베이스 그리고 매퍼 자체를 독립적으로 유지 + 객체와 데이터베이스 간에 데이터를 이동

      • SQL 구문의 파라미터와 결과(입력/출력)를 클래스에 매핑
    • 매핑방법

      • SQL 구문 - 입력과 출력으로 구분

        • 예) 입력 first_name, last_name / 출력 1234

          1. select first_name, last_name
            from employee
            where employee_number=1234;
        • XML 서술 파일 : SQL 구문의 입력과 출력을 매핑

          1. <select id="getAddress" parameterClass="int" resultClass="Address">
          2. select
          3. ADR_ID   as id,
          4. ADR_DESCRIPTION as description,
          5. ADR_STREET as street,
          6. ADR_CITY as city
          7. from address
          8. where ADR_ID = #id#
          9. </select>
          • 별칭 idsms id라고 불리는 Address 클래스의 프로퍼티에 매핑
          • #id# - 파라미터(Integer 형)
          • 위 코드를 수행하는 자바 코드

            1. Address addr = (Address) sqlMap.queryForObject("getAddress", new Integer(5));
          • 위 코드를 수행하는 C# 코드

            1. Address addr = (Address) sqlMap.queryForObject("getAddress", 5);
      • JDBC, ADO.NET 코드 작성 대신

        • 예) JDBC vs iBATIS

          • JDBC

            1. public Employee getEmployee (int id) throws SQLException {
                  Employee employee = null;
                  String sql = "SELECT * from employee " +
                          "where employee_number = ?";
                  Connection conn = null;
                  PreparedStatemnent ps = null;
                  ResultSet rs = null;
                  try {
                      conn = datasource.getConnection();
                      ps = conn.prepareStatement(sql);
                      ps.setInt(1, id);
                      rs = ps.executeQuery();
                      while (rs.next()) {
                          employee = new Employee();
                          employee.setId(rs.getInt("ID"));
                          employee.setEmployeeNumber(rs.getInt("EMPLOYEE_NUMBER"));
                          employee.setFirstName(rs.getString("FIRST_NAME"));
                          employee.setLastName(rs.getString("LAST_NAME"));
                          employee.setTitle(rs.getString("TITLE"));
                      }
                  } finally {
                      try {
                          if(rs != null) rs.close();
                      } filnally {
                          try {
                              if (ps != null) ps.close();
                          } filnally {
                              if (conn != null) conn.close();
                          }
                      }
                  }
                  return employee;
              }
          • iBATIS

            1. <select id="getEmployee" parameterClass="java.lang.Integer" resultClass="Employee">
            2. select
            3. ID               as id,
            4. EMPLOYEE_NUMBER   as description,
            5. FIRST_NAME   as street,
            6. LAST_NAME    as city
            7. TITLE         as title
            8. from employee
            9. where EMPLOYEE_NUMBER = #empNum#
            10. </select>
            • 실행 코드

              1. Employee emp = (Employee) sqlMap.queryForObject("getEmployee", new Integer(5));
  • (추가내용)

SQLMap.png

자바빈즈를 PreparedStatement 파라미터와 ResultSet으로 맵핑시켜주는 기능을 담당

 

  • 디미터 법칙(Law of Demeter) "각 계층은 다른 계층에 대해 오직 제한된 정보만을 가질 수 있다: 오직 현재 계층에 인접한 계층에 대해서만."

    • 각 계층이 오직 자기 바로 아래 계층과만 소통 가능
    • 의존성이 한 방향으로만 흐르는 것을 조장(스파게티 코드 피하기)
    • iBATIS는 퍼시스턴스 계층 프레임워크(위: 비지니스 로직 / 아래: 데이터베이스)

Spring과 iBATIS

  • 왜 iBATIS대신에 Spring을 사용할까?

    • iBATIS DAO 계층

      • 장점: 빠르고 쉬운 솔루션
      • BATIS SQL Maps / iBATIS DAO 계층 분리(2.3~)
      • 요구사항: 트랜잭션/커넥션 관리 -> Spring보다 훨씬 간단하게 사용가능한 프레임워크
      • 단점: 간결함
      • DAO 패턴을 사용: 결함도가 낮아짐(decoupling) -> 테스트하기 쉽다

        • Action에서 필요한 코드의 구현을 알 필요 없이 오직 필요한 인터페이스만 알면 됨.
        • 구현체는 설정을 통해 기워 넣게 됨
    • Spring : 커넥션과 트랜잭션 관리, 애플리케이션의 모든 부분에 적용(iBATIS DAO는DAO계층에만 적용)
  • 효율적인 DAO 계층

    • 구현체에서 인터페이스 분리

      • 이유

        1. 구현체 바꿔 치기가 가능(다른 형태의 데이터 접근 지원 가능)
        2. 테스트가 쉽고 빨리짐(실제 DB에 접근하는 객체 대신 가상의 DAO 객체를 끼워 넣을 수 있으므로)
      • IDE : 분리 과정 쉽게 처리 가능

        • 리팩토링 툴(클래스에서 인터페이스를 분리 가능)
        • 인터페이스를 만들 때 구현 클래스를 어떤 다른 데잍터베이스를 다루는 툴에 종속적인 부분에 노출 가능성 높음

          • 노출: DAO가 아닌 데이터 접근 구현체에 애플리케이션을 묶어버림

            • 예) 'Fast Lane Reader'패턴을 사용하는 웹 애플리케이션 - JDBC 코드가 뷰 계층과 직접 소통 (테스트 어려워짐)

              • -> 콜백을 사용해서 코드를 작성(뷰가 요청한 데이터를 처리하는 RowHanlder 같은 것)
          • SQL Maps API를 직접 사용하는 애플리케이션 -> 캡슐화된 API

            • 예) sqlMapClient 객체의 queryForList() 메소드를 호출하는 클래스 - > 작성한 DAO 클래스를 호출하게 리팩토링, 클래스의 메소드에서는 List 객체를 반환

              • 데이터 사용자 - 작성한 DAO하고만 소통 가능
    • 외부에서 설정된 팩토리(factory)를 사용하여 구현체의 결합도 낮추기

      • 인터페이스와 구현체 둘 다 DAO를 사용하는 클래스에 노출(인터페이스에 대한 의존성을 DAO를 사용하는 클래스에 추가한 셈)시키면 안됨

        • [구현체]-[DAO]-[interface]-> 구현체를 어떻게 사용할 수 있을 것인가?

          1. AccountDao accountDao = new AccountDaoImpl();   // DAO를 구현에서 분리, 구현체를 직접 참조하고 있음
          2. AccountDao accountDao = (AccountDao)DaoFactory.get(AccoutDao.class);   // 초점: DaoFacotry가 AccountDao 인테페이스를 구현한 객체를 반환
          • DAO factory

            • public인테피이스는 getInstance()와 getDao() 두개의 메소드로 이루어져 있음

              1. public class DaoFactory {
              2. private static DaoFatory instance = new DaoFactory();
              3. private final String defaultConfigLocation = "DaoFactory.properties";   // 프로퍼티 화일(인터페이스, 구현체 이름)
              4. private Properties daoMap;
              5. private Properties instanceMap;
              6. private String configLocation = System.getProperty(
              7. "dao.factory.config",

                defaultConfigLocation

                );

              8. private DaoFactory() {   // 1. private 생성자 선언(single tone; 오직 단 한 개의객체만 생성할 수 있는 클래스)
              9. daoMap = new Properties();
              10. instanceMap = new Properties();
              11. try {
              12. daoMap.load(getInputStream(configLocation));
              13. } catch (IOException e) {
              14. throw new RuntimeException(e);
              15. }
              16. private InputStream getInputStrream(String configLocation)
              17. {
              18. return Thread
              19. .currentThread()
              20. .getContextClassLoader()
              21. .getResourceAsStream(configLocation);
              22. }
              23. public static DaoFactory getInstance() {   // 2. 간단한 팩토리 메소드를 선언 (이 클래스의 유일한 인스턴스 반환)
              24. return instance;
              25. }
              26. public Object getDao(Class daoInterface) {   // 3. DAO를 가져온다 (인터페이스의 구현체를 반환)
              27. if (instanceMap.containsKey(daoInterface)) {
              28. return instanceMap.get(daoInterface);
              29. }
              30. return createDao(daoInterface);
              31. }
              32. private synchoronized Object createDao (Class daoInterface) {   // 4. 타입 별로 단 하나의 DAO만 생성함을 보장
              33. Class implementationClass;
              34. try {
              35. implementationClass = Class.forName((String)daoMap.get(daoInterface));
              36. Object implementation = implementationClass.newInstance();
              37. instanceMap.put(implementationClass, implementation);
              38. } catch (Exception e) {
              39. throw new RuntimeException(e);
              40. }
              41. return instanceMap.get(daoInterface);         // DAO에 대한 실제 요청이 발생할 때에 생성
              42. }
              43. }

               

            •  
      • 트랜잭션과 커넥션 관리기능 제공(chap. 7)
    • 스프링: 데이터 매퍼의 두 가지 버전(1.3, 2.0)을 지원

      • 버전 1.3 : SqlMapXxx (SqlMapTemplate 클래스 사용)
      • 버전 2.0 : SqlMapClientXxx (SqlMapClientTemplate 클래스 사용: 내부적으로 iBATIS의 SqlMapClient 사용)

        • SqlMapClient를 스프링 빈으로 설정 : SqlMapClientFactoryBean 클래스 이용

          1. <bean id="sqlMapClinet" class="org.springframework.orm.ibatis.SqlMapClinetFactoryBean"

            • p:dataSource-fef="dataSource"
            • p:configLocation="WEB-INF/sqlMap/sqlMapConfig.xml">
          2. </bean>
        • sqlMapConfig.xml

          1. <?xml version="1.0" encoding="UTF-8" ?>
          2. <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
          3. "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
          4. <sqlMapConifg>
          5. <sqlMap resource="GuestBook.xml" />
          6. </sqlMapConifg>
        • GuestBook.xml

          1. <?xml version="1.0" encoding="UTF-8" ?>
          2. <!DOCTYPE sqlMap
          3. PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
          4. "http://ibatis.apache.org/dtd/sql-map-2.dtd">
          5. <sqlMap namespace="Guestbook">
          6. <typeAlias alias="Message" type="kame.spring.questbook.service.Message" />

            <parameterMap id="messageParamMap" class="Message">

          7. <parameter property="guestName" />
          8. </parameterMap>
          9. <resultMap id="messageResultMap" class="Message">
          10. <result property="id" column="GUESTBOOK_MESSAGE_ID" />
          11. <result property="guestName" column="GUEST_NAME" />
          12. <result property="content" column="CONTENT" />
          13. </reslutMap>
          14. ..
          15. <select id="selectList" resultMap="messageReusltMap" resultClass="Message" parameterCalss="map">
          16. select * from GUESTBOOK_MESSAGE order by GUESTBOOK_MESSAGE_ID desc limit #startRow#, #fetchSize#
          17. </select>
          18. </sqlMap>
        • limit 는 mySql에 있다.

     

    바깥고리

    자바 프레임워크 활용 전략


    JDeveloper에서 iBATIS 실행하기

    자동으로 클래스패스를 잡아주니 라이브러리에 추가만 해주면 된다.

    1. Library Name에 알기 쉬운 이름을 붙여준다(iBATIS2.3.0.677)

    include_lib2.png

     

    include_lib.png

     


    iBATIS를 통해 더 즐겁게 개발하고, 또 개발의 재미도 느끼고 야근도 덜 할 수 있기를 기원한다. - xx

    불가지론자(경험해보지 않은 것은 믿을 수 없다) - xxi

    "망치를 가진 사람은 모든 것을 못으로 본다" , 환경이 다양하면 다양한 도구가 필요한 법 - xxii

    책을 쓰는 것은 (소프트웨어를 작성)하는 것보다 더 어렵다. - xxiv

    돈을 위해 낮에는 일을 하고 명성과 영광을 얻기 위해 밤에는 오픈소스 소프트웨어(또는 책)를 작성하기 위해 시간을 보낸다.(클린턴 비긴) - xxiv

    긱(geek: 학업이나 일, 컴퓨터 등에 몰두하다 보니 세상물정과는 거리가 멀어진 사람 / 특정 분야에 대해 광적인 사람), 우리는 첫 번째 컴퓨터를 가졌을때의 좋은 기억이 있고 그 컴퓨터를 사주는 투자가 나중에 좋은 결과를 낳게 된다는 것을 아는 부모님을 신뢰한다. - xxv

    은 무언가를 배우는 최고의 방법, 종이책이 전자책으로 대체되거나 뒤통수에 잭을 꼽아서 몇 초안에 정보를 업로드하는 방식으로 바뀔 거라는 등 많은 억측, 나는 책을 좋아한다. 책은 편리하게 갖고 다닐 수 있고, 다루기도 쉽기 때문이다. 책에 메모를 남기고, 종이를 접고, 반으로 쪼개서 갖고 다닐 수도 있다.(클린턴 비긴) - xxvii

     사람들은 스스로 동기를 부여받아 탐구하는 동안 배운 것들을 기억(인지 과학), 인류는 행동하며(in action) 배운다. - xxxii

     

    노하우

    db.properties 위치

    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    «   2025/04   »
    1 2 3 4 5
    6 7 8 9 10 11 12
    13 14 15 16 17 18 19
    20 21 22 23 24 25 26
    27 28 29 30
    글 보관함