MyBatis

2012. 7. 3. 14:20

Deprecated. (구버전, 교체됨)

Version 3를 사용하세요~

 

MyBatis에서 특정 테이블의 컬럼목록 가져오기

가끔 특정 테이블의 컬럼의 목록을 구할 필요가 있을 때가 있다. DBMS에서 테이블의 정보를 구해오는 것은 각각의 DB마다 상이하다. (예. 오라클의 경우는 딕셔너리 테이블에서 가져올 수 있다) JDBC의 메타데이터를 이용하면 쉽게 가져올 수 있다.

참고 : Get column names of a table using ResultSetMetaData

그럼 MyBatis를 사용해서 DB Mapper를 사용하는 경우 별도의 JDBC 연결 설정을 만들어서 이용해야 하나?

그러면 DB 접속 환경이 한군데가 변하게 되면 MyBatis 및 JDBC 모두 변경을 해야 한다. 이것은 중복이다. DRY원칙 위반이다. 설정값을 하나로 이용하는 방법도 있지만 이것 역시 귀찮다.

 

쉬운방법으로는 SqlSessionFactory에서 openSession() 메소드를 통해 세션을 연 다음 SqlSession 인터페이스에서

getConnection() 메소드를 이용하여 java.sql.Connection을 가져오면 JDBC의 기능을 온전히 이용할 수 있다.

말로만 설명하면 어려우니 예제를 보여주겠습니다.

  1. SqlSession session = sqlMapper.openSession();   // sqlMapper는 SqlSessionFactory 타입입니다.
  2. try {
  3. Statement statement = session.getConnection().createStatement();
    ResultSet resultSet = statement.executeQuery("SELECT * FROM someTabe WHERE 0=1");
    ResultSetMetaData metadata = resultSet.getMetaData();
    int columnCount = metadata.getColumnCount();
  4. ArrayList<String> columns = new ArrayList<String>();
    for (int i = 1; i < columnCount; i++) {
     String columnName = metadata.getColumnName(i);
     columns.add(columnName);
    }
  5. } finally {

    session.close();

    }

위에서 보면 columns라는 ArrayList타입의 리스트에 컬럼명을 넣습니다.

executeQuery에서 'WHERE 0=1'로 거짓조건을 주는 이유는 데이터를 가져오지 않게 하기 위함입니다.

columns를 이용해서 컬럼 목록을 이용하면 됩니다. 

이름의 변경

SQL 매핑 프레임워크 iBATIS가 이름이 MyBatis로 바뀌었다.

클린턴 비긴이 처음 개발했던 아이바티스는 아파치 프로젝트로 들어갔다가 2010년 6월 16일 은퇴(retire)하고 구글 코드쪽에서mybatis라는 이름으로 이동했다. 지금 시점(2010 12월)에서는 MyBatis 3.0.3 버전이 릴리즈 되어 있다.

SQL 주입(injection)에 대한 기사

“카드 정보 1억 3,000만 건 도난”, 주범은 SQL 인젝션

 

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=""xmlxmlResultName="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_namelast_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 위치

 

 

'스프링3.0' 카테고리의 다른 글

contextConfigLocation  (0) 2012.07.04
스프링 3.0 + ibatise  (0) 2012.07.03
Srping 3.0 sqlSession+DataSource 구현 하기. (Spring+mybatise0  (0) 2012.05.19
web.xml 구현부 encoder  (0) 2012.05.19
Spring 개발 환경 .  (0) 2012.05.19
Posted by 사라링
BLOG main image
.. by 사라링

카테고리

사라링님의 노트 (301)
JSP (31)
J-Query (41)
JAVA (24)
VM-WARE (0)
디자인패턴 (1)
스크랩 (0)
스트러츠 (3)
안드로이드 (11)
오라클 (45)
우분투-오라클 (1)
이클립스메뉴얼 (6)
스프링3.0 (23)
자바스크립트 (10)
HTML5.0 (17)
정보처리기사 (1)
기타(컴퓨터 관련) (1)
문제점 해결 (3)
프로젝트 (2)
AJAX (4)
하이버네이트 (3)
트러스트폼 (11)
Jeus (2)
재무관리(회계) (5)
정규식 (5)
아이바티스 (8)
취미 (2)
소프트웨어 보안 관련모음 (0)
정보보안기사 (6)
C언어 베이직 및 프로그램 (3)
보안 관련 용어 정리 (2)
넥사크로 (6)
Total :
Today : Yesterday :