iBATIS-SqlMaps-2

Similar documents
Microsoft PowerPoint - ibatis.pptx

iBATIS-SqlMaps-2

iBATIS-SqlMaps-2

iBATIS-SqlMaps-2-Tutorial

C# Programming Guide - Types

PowerPoint Presentation

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

< 목차 > 1. Data Access Service 개요 (ibatis 활용 ) 3. DBIO 소개

쉽게 풀어쓴 C 프로그래밊

Spring Boot/JDBC JdbcTemplate/CRUD 예제

JDBC 소개및설치 Database Laboratory

JVM 메모리구조

PowerPoint Presentation

JAVA PROGRAMMING 실습 05. 객체의 활용

- JPA를사용하는경우의스프링설정파일에다음을기술한다. <bean id="entitymanagerfactory" class="org.springframework.orm.jpa.localentitymanagerfactorybean" p:persistenceunitname=

Bind Peeking 한계에따른 Adaptive Cursor Sharing 등장 엑셈컨설팅본부 /DB 컨설팅팀김철환 Bind Peeking 의한계 SQL 이최초실행되면 3 단계의과정을거치게되는데 Parsing 단계를거쳐 Execute 하고 Fetch 의과정을통해데이터

gnu-lee-oop-kor-lec06-3-chap7

q 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2

InsertColumnNonNullableError(#colName) 에해당하는메시지출력 존재하지않는컬럼에값을삽입하려고할경우, InsertColumnExistenceError(#colName) 에해당하는메시지출력 실행결과가 primary key 제약에위배된다면, Ins

PowerPoint Presentation

ALTIBASE 사용자가이드 Templete

MyBatis

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

제11장 프로세스와 쓰레드

@OneToOne(cascade = = "addr_id") private Addr addr; public Emp(String ename, Addr addr) { this.ename = ename; this.a

Connection 8 22 UniSQLConnection / / 9 3 UniSQL OID SET

JAVA PROGRAMMING 실습 08.다형성

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

쉽게 풀어쓴 C 프로그래밍

1. auto_ptr 다음프로그램의문제점은무엇인가? void func(void) int *p = new int; cout << " 양수입력 : "; cin >> *p; if (*p <= 0) cout << " 양수를입력해야합니다 " << endl; return; 동적할

PowerPoint 프레젠테이션

chap 5: Trees

Microsoft Word - ntasFrameBuilderInstallGuide2.5.doc

목차 BUG 문법에맞지않는질의문수행시, 에러메시지에질의문의일부만보여주는문제를수정합니다... 3 BUG ROUND, TRUNC 함수에서 DATE 포맷 IW 를추가지원합니다... 5 BUG ROLLUP/CUBE 절을포함하는질의는 SUBQUE

DBMS & SQL Server Installation Database Laboratory

Microsoft PowerPoint - 10Àå.ppt

PowerPoint Presentation

JUNIT 실습및발표

PowerPoint Template

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

Microsoft PowerPoint - chap01-C언어개요.pptx

10.ppt

17장 클래스와 메소드

Microsoft PowerPoint - CSharp-10-예외처리

금오공대 컴퓨터공학전공 강의자료

C++ Programming

untitled

PowerPoint Template

어댑터뷰

교육자료

PowerPoint 프레젠테이션

(jpetstore \277\271\301\246\267\316 \273\354\306\354\272\270\264\302 Spring MVC\277\315 iBatis \277\254\265\277 - Confluence)

강의 개요

Data Sync Manager(DSM) Example Guide Data Sync Manager (DSM) Example Guide DSM Copyright 2003 Ari System, Inc. All Rights reserved. Data Sync Manager

FileMaker 15 ODBC 및 JDBC 설명서

ThisJava ..

Spring Boot

Microsoft PowerPoint 자바-기본문법(Ch2).pptx

Windows 8에서 BioStar 1 설치하기

슬라이드 1

Spring Data JPA Many To Many 양방향 관계 예제

PowerPoint Presentation

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

Microsoft PowerPoint - 2강

PowerPoint Presentation

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

학습목표 함수프로시저, 서브프로시저의의미를안다. 매개변수전달방식을학습한다. 함수를이용한프로그래밍한다. 2

MySQL-.. 1

WINDOW FUNCTION 의이해와활용방법 엑셈컨설팅본부 / DB 컨설팅팀정동기 개요 Window Function 이란행과행간의관계를쉽게정의할수있도록만든함수이다. 윈도우함수를활용하면복잡한 SQL 들을하나의 SQL 문장으로변경할수있으며반복적으로 ACCESS 하는비효율역

<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

PowerPoint 프레젠테이션

Eclipse 와 Firefox 를이용한 Javascript 개발 발표자 : 문경대 11 년 10 월 26 일수요일

설계란 무엇인가?

Apache Ivy

FileMaker ODBC 및 JDBC 가이드

쉽게 풀어쓴 C 프로그래밍

슬라이드 1

Network Programming

13주-14주proc.PDF

Microsoft PowerPoint - ch07 - 포인터 pm0415

JAVA Bean & Session - Cookie

쉽게 풀어쓴 C 프로그래밍

arcplan Enterprise 6 Charting Facelifts

PowerPoint 프레젠테이션

<4D F736F F F696E74202D E DB0FCB0E820BBE7BBF3BFA120C0C7C7D120B0FCB0E820B5A5C0CCC5CDBAA3C0CCBDBA20BCB3B0E8>

adfasdfasfdasfasfadf

기술문서 작성 XXE Attacks 작성자 : 인천대학교 OneScore 김영성 I. 소개 2 II. 본문 2 가. XML external entities 2 나. XXE Attack 3 다. 점검방법 3 라.

Microsoft PowerPoint - Chap12-OOP.ppt

TITLE

02 C h a p t e r Java

Microsoft PowerPoint - chap06-2pointer.ppt

JAVA PROGRAMMING 실습 09. 예외처리

07 자바의 다양한 클래스.key

* Factory class for query and DML clause creation * tiwe * */ public class JPAQueryFactory implements JPQLQueryFactory private f

Microsoft PowerPoint - C++ 5 .pptx

Microsoft PowerPoint - Introduction to Google Guava.pptx

PowerPoint Template

PowerPoint Presentation

Chap7.PDF

Transcription:

Data Mapper (a.k.a SQL Maps) Version 2.0 개발자가이드 2006 년 3 월 11일 번역 : 이동국 (fromm0@gmail.com) 오타및오역은위메일주소로보내주시기바랍니다. 1

소개 ibatis Data Mapper 프레임워크는당신이관계형데이터베이스에접근할때필요한자바코드를현저하게줄일수있도록도와줄것이다. ibatis 는간단한 XML 서술자를사용해서간단하게자바빈즈를 SQL statement 에맵핑시킨다. 간단함 (Simplicity) 이란다른프레임워크와객체관계맵핑툴에비해 ibatis 의가장큰장점이다. ibatis Data Mapper 를사용하기위해서당신은자바빈즈와 XML 그리고 SQL 에친숙할필요가있다. 여기엔배워야할것도거의없고테이블을조인하거나복잡한쿼리문을수행하기위해필요한복잡한스키마도없다. Data Mapper 를사용하면당신은실제 SQL 문의모든기능을가질수있다. Data Mapper (com.ibatis.sqlmap.*) 개념 ibatis Data Mapper API 는프로그래머에게자바빈즈객체를 PreparedStatement 파라미터와 ResultSets 으로쉽게맵핑할수있도록한다. Data Mapper 의기본적인생각은간단함 (simple) 이다. 이는자바코드의 20% 를사용하여 JDBC 기능의 80% 를제공하는간단한프레임워크라는뜻이다. 이것은어떻게작동하는가.? Data Mapper 는자바빈즈, Map 구현, 원시래퍼타입 (String, Integer ) 그리고 SQL 문을위한 XML 문서를맵핑하기위한 XML 서술자를사용하는매우간단한프레임워크를제공한다. 다음은생명주기에대한높은레벨의서술이다. 1) 파라미터 ( 자바빈즈, Map 또는원시래퍼 ) 로써객체를제공한다. 파라미터객체는 update 문내에입력값을셋팅하기위해사용되거나쿼리문의 where 절을셋팅하기위해서사용된다. 2) 맵핑된 statement 을실행한다. 이단계는마법이일어나는곳이다. Data Mapper 프레임워크는 PreparedStatement 인스턴스를생성할것이고제공된파라미터객체를사용해서파라미터를셋팅한다. 그리고 statement 를실행하고 ResultSet 으로부터결과객체를생성한다. 3) update 의경우에영향을미친 rows 의숫자를반환한다. 조회문일경우에한개 (single) 의객체또는컬렉션객체를반환한다. 파라미터처럼결과객체는자바빈즈, Map 원시타입래퍼또는 XML 이될수있다. 밑의다이어그램은서술된것을설명한다. 2

설치 ibatis Data Mapper 프레임워크설치는간단하게클래스패스에필요한 JAR 파일을두면된다. 이것은 JVM 시작시정의된클래스패스에두거나웹애플리케이션의 /WEB-INF/lib 에둘수도있다. 자바클래스패스에대해서는다음의자원을참조하라. http://java.sun.com/j2se/1.4/docs/tooldocs/win32/classpath.html http://java.sun.com/j2se/1.4.2/docs/api/java/lang/classloader.html http://java.sun.com/j2se/1.4.2/docs/ ibatis 는다음의 JAR 파일을가진다. 파일명 상세설명 필수여부 ibatis-common.jar ibatis Common Utilities YES ibatis-sqlmap.jar ibatis Data Mapper Framework YES ibatis-dao.jar ibatis Data Access Objects Framework. NO JAR 파일과의존성 프레임워크가너무많은의존성을가진다면이것은애플리케이션이나다른프레임워크에통합되기힘들게만든다. 2.0 의중요한핵심사항은의존성관리와제거의중점을두었다. 그러므로만약당신이 jdk1.4 를사용한다면실제의존적인것은 Jakarta Commons Logging 프레임워크뿐이다. 이추가적인 JAR 파일은배포판의 /lib/optional 디렉토리에서찾을수있다. 그들은기능에의해분류된다. 다음은추가적인패키지를사용할때필요한것들의목록이다. Description When to Use Directories Legacy JDK Support ibatis Backward Compatibility Runtime Bytecode Enhancement DataSource Implementation Distributed 만약에당신이 JDK1.4 보다하위버전을사용하고당신의애플리케이션서버가이런 JAR 파일을제공하지않는다면당신은이런옵션패키지가필요할것이다. 당신이 ibatis 의예전버전 DAO(1.x) 프레임워크를사용하고있거나 SQL Maps(1.x) 의예전버전을사용하고있다면이디렉토리의 JAR 파일을간단하포함시킴으로써계속작업을할수있다. 만약당신이늦은 (lazy) 로딩과성능에대해고려하기위한 CGLIB2.0 bytecode 개선을사용하길원한다면당신이 Jakarta DBCP Connection pool을사용하길원한다면중앙집중적이거나분산캐슁지원을위한 JDBC 2.0 Extensions http://java.sun.com/products/jdbc/download.html JTA 1.0.1a http://java.sun.com/products/jta/ Xerces 2.4.0 http://xml.apache.org/xerces2-j/ ibatis DAO 1.3.1 http://sourceforge.net/projects/ibatisdb/ CGLIB 2.0 http://cglib.sf.net DBCP 1.1 http://jakarta.apache.org/commons/dbcp/ OSCache 2.0.1 http://www.opensymphony.com/oscache/ Caching OSCache 를사용하길원한다면 Logging Solution Log4J 로깅을사용하길원한다면 Log4J 1.2.8 http://logging.apache.org/log4j/docs/ 1.x 에서업그레이드하기당신은업그레이드할것인가.? 만약당신이업그레이드를시도한다면결정할수있는가장좋은방법이다. 여기에몇가지업그레이드절차가있다. 3

1. 버전 2.0 은 1.x 릴리즈와거의완벽한호완성을가지도록유지되었다. 그래서몇몇사람들에게는단순히 JAR 파일만교체하는것으로충분할것이다. 이것은최소한의이득을발생시키지만가장간단하다. 당신은당신의 XML 파일이나자바코드를변경할필요가없다. 몇몇모순되는것들이발견될지도모른다. 2. 두번째는당신의 XML파일을 2.0스펙에적합하도록변경하는것이다. 하지만이는 1.x 자바 API를그대로사용한다. 적은호환성이슈내안전한해결법은맵핑파일사이에발생한다. Ant 작업은당신을위해 XML 파일을변환하기위해서프레임워크에포함된다. 3. 4. 세번째옵션은당신의 XML 파일과자바코드를변환하는것이다. 자바코드를변환하기위한툴은없다. 그래서이것은손으로직접해야한다. 마지막옵션은전체를업그레이드하지않는것이다. 만약에당신이어렵다고느낀다면 1.x 릴리즈에서시스템이작동하는것을두려워하지마라. 당신의오래된애플리케이션을그대로놔두는것은나쁜생각이아니다. 만약에오래된애플리케이션이인식적인면에서제대로리팩토링되어있다면당신은 SQL Maps 를업그레이드잘할수있을것이다. 1.x 에서 2.x 으로 XML 설정파일변환하기 2.0 프레임워크는 Ant 빌드시스템을통해수행되는 XML 문서변환기를포함한다. 당신의 XML 문서를변환하는것은 1.x코드가작동중에자동으로오래된 XML 파일을변환하는것처럼옵션적이다. 여전히당신이업그레이드를함으로써편안하게당신의파일을변환하는것이좋은생각이다. 당신은다소적은호환적인이슈를경험할것이고새로운기능중몇개의장점을얻을수있을것이다 ( 비록당신이 1.x 자바 API 을사용하더라도.). Ant 작업은당신의 build.xml 파일내에다음과비슷하게보일것이다. <taskdef name="convertsqlmaps" classname="com.ibatis.db.sqlmap.upgrade.converttask" classpathref="classpath"/> <target name="convert"> <convertsqlmaps todir="d:/targetdirectory/" overwrite="true"> <fileset dir="d/sourcedirectory/"> <include name="**/maps/*.xml"/> </fileset> </convertsqlmaps> </target> 당신이보는것처럼이것은 Ant 복사작업과거의같고사실이것은 Ant 복사작업을확장한것이다. 그래서당신은복사하는작업을하는어떤것도할수있다. JAR 파일들 : 예전것을빼내고새것을넣자. 업그레이드를할때존재하는 ( 예전의 ) ibatis 파일과의존적인것들을모두지우고새파일을대체하는것이좋은생각이다. 여전히필요한당신의다른컴포넌트또는프레임워크를모두지우지않도록주의해라. JAR 파일의대부분은당신환경에의존적이다. JAR 파일과의존적인것에대해서는위에서서술된것을보아라. 다음의테이블은예전파일과새파일을목록화한다. Old Files New Files 4

ibatis-db.jar 1.2.9b 버전에서부터이파일은다음의 3 개의파일로분리되었다. ibatis-common.jar ibatis-dao.jar ibatis-sqlmap.jar commons-logging.jar commons-logging-api.jar commons-collections.jar commons-dbcp.jar commons-pool.jar oscache.jar jta.jar jdbc2_0-stdext.jar xercesimpl.jar xmlparserapis.jar jdom.jar ibatis-common.jar ( 필수 ) ibatis-sqlmap.jar ( 필수 ) ibatis-dao.jar (DAO 프레임워크를사용하는것에따라옵션 ) commons-logging-1-0-3.jar ( 필수 ) commons-collections-2-1.jar ( 옵션 ) commons-dbcp-1-1.jar ( 옵션 ) commons-pool-1-1.jar ( 옵션 ) oscache-2-0-1.jar ( 옵션 ) jta-1-0-1a.jar ( 옵션 ) jdbc2_0-stdext.jar ( 옵션 ) xercesimpl-2-4-0.jar ( 옵션 ) xmlparserapis-2-4-0.jar ( 옵션 ) xalan-2-5-2.jar ( 옵션 ) log4j-1.2.8.jar ( 옵션 ) cglib-full-2-0-rc2.jar ( 옵션 ) 이가이드의나머지는당신이 SQL Maps 를사용하는것에대해소개할것이다. SQL Map XML 설정파일 (http://ibatis.apache.org/dtd/sql-map-config-2.dtd) SQL Maps 는데이터소스, 데이터맵퍼에대한설정, 쓰레드관리와같은 SQL Maps 와다른옵션에대한설정을제공하는중앙집중적인 XML 설정파일을사용해서설정된다. 다음은 SQL Maps 설정파일의예이다. SqlMapConfig.xml <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sqlmapconfig PUBLIC "-//ibatis.apache.org//dtd SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <!-- 다음은정확한 XML 헤더를위한필수값이다. --> <sqlmapconfig> <!-- 여기서명시된파일내프라퍼티 (name=value) 는이설정파일내고정자 (placeholder) 에의해사용될수있다. ( 이를테면. ${driver}. 이파일은클래스패스에상대적이고선택적인사항이다. --> <properties resource=" examples/sqlmap/maps/sqlmapconfigexample.properties " /> <!-- 이셋팅은가장기본적으로는트랜잭션관리를하며 SqlMapClient 설정상세를제어한다. 이것들은모두선택적이다. --> <settings cachemodelsenabled="true" enhancementenabled="true" lazyloadingenabled="true" maxrequests="128" maxsessions="10" maxtransactions="5" usestatementnamespaces="false" /> 5

<!-- 긴전체경로를포함한클래스명을위한좀더짧은이름을사용하기위한별칭을타이핑한다. --> <typealias alias="order" type="testdomain.order"/> <!--SimpleDataSource 를이용한 SQL Map 를사용하기위한데이터소스설정. 위자원으로부터프라퍼티사용에주의할. --> <transactionmanager type="jdbc" > <datasource type="simple"> <property name="jdbc.driver" value="${driver}"/> <property name="jdbc.connectionurl" value="${url}"/> <property name="jdbc.username" value="${username}"/> <property name="jdbc.password" value="${password}"/> <property name="jdbc.defaultautocommit" value="true" /> <property name="pool.maximumactiveconnections" value="10"/> <property name="pool.maximumidleconnections" value="5"/> <property name="pool.maximumcheckouttime" value="120000"/> <property name="pool.timetowait" value="500"/> <property name="pool.pingquery" value="select 1 from ACCOUNT"/> <property name="pool.pingenabled" value="false"/> <property name="pool.pingconnectionsolderthan" value="1"/> <property name="pool.pingconnectionsnotusedfor" value="1"/> </datasource> </transactionmanager> <!-- 이 SQL map 에의해로드되는모든 SQL Map 파일을인식한다. 경로는클래스패스에상대적이다. --> <sqlmap resource="examples/sqlmap/maps/person.xml" /> </sqlmapconfig> 이문서의다음부분은 SQL Maps 설정파일의다양한부분을논의한다. <properties> 요소 SQL Maps 은 SQL Maps XML 설정파일과함께속하는표준적인자바속성파일 (name=value) 을지정하는하나의 <properties> 요소를가질수있다. 그렇게함으로써속성파일내에각각의이름지어진값들은 SQL Maps 설정파일내에참조될수있는변수가될수있고모든 SQL Maps 는내부에서참조된다. 예를들면속성파일이다음을포함한다면 driver=org.hsqldb.jdbcdriver 그러면 SQL Maps 설정파일또는설정문서에의해참조되는각각의 SQL Maps 는 ${driver} 형태로사용가능하고 org.hsqldb.jdbcdriver 라는값이참조된다. 예를들면 <property name="jdbc.driver" value="${driver}"/> 이것은빌드되거나테스트그리고배치되는동안편리하게된다. 이것은다중환경이나설정파일을위한자동화툴을사용하는당신의애플리케이션을쉽게인식하도록한다. 프라퍼티는클래스패스나어떤유효한 URL 로부터로드될수있다. 예를들면고정된파일경로를위해다음처럼사용한다. <properties url= file:///c:/config/my.properties /> <settings> 요소 <settings> 요소는 XML 파일을빌드하는 SqlMapClient 인스턴스를위해다양한옵션과최적화를설정하도록한다. setting요소와그것의모든속성값은모두옵션적이다. 제공되는속성값과그것들의다양한행위는다음의테이블에서서술된다. maxrequests 이것은한꺼번에 SQL 문을수행할수있는쓰레드의수이다. 셋팅값보다많 6

은쓰레드는다른쓰레드가수행을완료할때까지블록된다. 다른 DBMS는다른제한을가진다. 이것은최소한 10 개의 maxtransactions 이고언제나 maxsessions 과 maxtransactions 보다크다. 종종동시요청값의최대치를줄이면성능향상을보여준다. maxsessions 예 : maxrequests= 256 Default: 512 이것은주어진시간동안활성될수있는세션의수이다. 세션은명시적으로주어질수도있고프로그램적으로요청될수도있고쓰레드가 SqlMapClient 인스턴스를사용할때마다자동적으로생성될수도있다. 이것은언제나 maxtransaction 보다같거나커야하고 maxrequests 보다작아야한다. 동시세션값의최대치를줄이면전체적인메모리사용량을줄일수있다. 예 : maxsessions= 64 Default: 128 maxtransactions 이것은한꺼번에 SqlMapClient.startTransaction() 에들어갈수있는쓰레드의최대갯수이다. 셋팅값보다많은쓰레드는다른쓰레드가나올때까지블록된다. 다른 DBMS 는다른제한을가진다. 이값은언제나 maxsessions보다작거나같아야하고 maxrequests 보다작아야한다. 종종동시트랜잭션의최대치를줄이면성능향상을보여준다. 예 : maxtransactions= 16 Default: 32 cachemodelsenabled 이셋팅은 SqlMapClient 를위한모든캐쉬모델을가능하게하거나가능하지않게한다. 이것은디버깅시도움이된다. 예 : cachemodelsenabled= true Default: true (enabled) lazyloadingenabled 이셋팅은 SqlMapClient 를위한모든늦은 (lazy) 로딩을가능하게하거나가능하지않게한다. 이것은디버깅시도움이된다. 예 : lazyloadingenabled= true Default: true (enabled) enhancementenabled 이셋팅은향상된늦은 (lazy) 로딩처럼최적화된자바빈즈속성접근을위해런타임시바이트코드향상을가능하게한다. 예 : enhancementenabled= true Default: false (disabled) usestatementnamespaces 이셋팅을가능하게하면당신은 sqlmap 이름과 statement 이름으로구성된전체적인이름 (fully qualified name) 으로맵핑된 statement 를참조해야한다. 예를들면 : queryforobject( sqlmapname.statementname ); 예 : usestatementnamespaces= false Default: false (disabled) <typealias> 요소 7

typealias 요소는긴전체경로를포함한클래스명을참조하기위한짧은이름을명시하도록한다. 예를들면 <typealias alias="shortname" type="com.long.class.path.class"/> SQL Maps 설정파일에서사용되는미리정의된몇몇 alias 가있다. 그것들은 Transaction Manager Aliases JDBC com.ibatis.sqlmap.engine.transaction.jdbc.jdbctransactionconfig JTA com.ibatis.sqlmap.engine.transaction.jta.jtatransactionconfig EXTERNAL com.ibatis.sqlmap.engine.transaction.external.externaltransactionconfig Data Source Factory Aliases SIMPLE DBCP JNDI <transactionmanager> 요소 com.ibatis.sqlmap.engine.datasource.simpledatasourcefactory com.ibatis.sqlmap.engine.datasource.dbcpdatasourcefactory com.ibatis.sqlmap.engine.datasource.jndidatasourcefactory 1.0 변환노트 : SQL Maps 1.0 은다중의데이터소스설정을허락했다. 이것은다루기어렵고몇가지나쁜예제를소개했다. 그러므로 2.0 에서는오직하나의데이터소스만을허락한다. 다중의배치 / 설정을위해서는시스템에의해다르게설정되거나 SQL Maps 를빌드할때파라미터처럼전달되는다중속성파일이추천된다. <transactionmanager> 요소는당신이 SQL Maps 를위한트랜잭션관리를설정하도록한다. type 속성값은사용하기위한트랜잭션관리자를표시한다. 그값은클래스명이거나타입 alias 일수있다. 3 개의트랜잭션관리자는 JDBC, JTA 그리고 EXTERNAL 중에하나로표시할수있다. JDBC Connection commit() 과 rollback() 메소드를통해트랜잭션를제어하기위한 JDBC 를사용하게된다. JTA 이트랜잭션관리자는 SQL Maps 가다른데이터베이스나트랜잭션자원을포함하는더욱더넓은범위의트랜잭션을포함하도록하는 JTA 전역트랜잭션를사용한다. 이설정은 JNDI 자원으로부터사용자트랜잭션을위치시키기위한 UserTransaction 속성값을요구한다. JNDI 데이터소스예제는다음의설정예제에서보라. EXTERNAL 이것은당신자신이트랜잭션을관리하도록한다. 당신은여전히데이터소스를설정할수있지만프레임워크생명주기의부분처럼트랜잭션이커밋되거나롤백되지않는다. 이것은당신애플리케이션의부분이외부적으로 SQL Maps 트랜잭션을관리해야한다는것이다. 이셋팅은비-트랜잭션 ( 예를들면읽기전용 ) 데이터베이스에유용하다. <datasource> 요소트랜잭션관리자설정의포함된부분은 datasource 요소이고 SQL Maps 를사용하기위한데이터소스를설정하기위한속성값의집합이다. 여기엔프레임워크에서제공되는 3 가지데이터소스타입이있지만당신은당신만의데이터소스를사용할수도있다. 포함된 DataSourceFactory 구현은다음에상세하게논의가될것이고각각을위해제공되는설정은아래예제를보라. SimpleDataSourceFactory SimpleDataSource 는데이터소스를제공하는컨테이너가없는경우에 connection 을제공하기위해기본적으로풀링 (pooling) 데이터소스구현을제공한다. 이것은 ibatis SimpleDataSource connection 풀링을기초로한다. <transactionmanager type="jdbc"> <datasource type="simple"> <property name="jdbc.driver" value="org.postgresql.driver"/> <property name="jdbc.connectionurl" value="jdbc:postgresql://server:5432/dbname"/> <property name="jdbc.username" value="user"/> <property name="jdbc.password" value="password"/> <!--OPTIONAL PROPERTIES BELOW --> <property name="pool.maximumactiveconnections" value="10"/> 8

<property name="pool.maximumidleconnections" value="5"/> <property name="pool.maximumcheckouttime" value="120000"/> <property name="pool.timetowait" value="10000"/> <property name="pool.pingquery" value="select * from dual"/> <property name="pool.pingenabled" value="false"/> <property name="pool.pingconnectionsolderthan" value="0"/> <property name="pool.pingconnectionsnotusedfor" value="0"/> </datasource> </transactionmanager> DbcpDataSourceFactory 이구현물은 DataSource API 를통해 connection 풀링서비스를제공하기위해 Jakarta DBCP (Database Connection Pool) 을사용한다. 이 DataSource 는애플리케이션 / 웹컨테이너가 DataSource 구현물을제공하지못하거나당신이 standalone 애플리케이션을구동할때이상적이다. DbcpDataSourceFactory 를위해명시해야하는설정파라미터의예제는다음과같다. <transactionmanager type="jdbc"> <datasource type="dbcp"> <property name="jdbc.driver" value="${driver}"/> <property name="jdbc.connectionurl" value="${url}"/> <property name="jdbc.username" value="${username}"/> <property name="jdbc.password" value="${password}"/> <!--OPTIONAL PROPERTIES BELOW --> <property name="pool.maximumactiveconnections" value="10"/> <property name="pool.maximumidleconnections" value="5"/> <property name="pool.maximumwait" value="60000"/> <!--Use of the validation query can be problematic. If you have difficulty, try without it. --> <property name="pool.validationquery" value="select * from ACCOUNT"/> <property name="pool.logabandoned" value="false"/> <property name="pool.removeabandoned" value="false"/> <property name="pool.removeabandonedtimeout" value="50000"/> <property name="driver.driverspecificproperty" value="somevalue"/> </datasource> </transactionmanager> JndiDataSourceFactory 이구현물은애플리케이션컨테이너내 JNDI 컨텍스트로부터 DataSource 구현물을가져와야할것이다. 이것은전형적으로애플리케이션서버를사용중이고컨테이너관리 connection pool 그리고제공되는 DataSource 구현물이있을때사용한다. JDBC DataSource 구현물에접근하기위한표준적인방법은 JNDI 컨텍스트를통하는것이다. JndiDataSourceFactory 는 JNDI 를통해 DataSource 에접근하는기능을제공한다. 데이터소스내에명시되어야하는설정파라미터는다음과같다. <transactionmanager type="jdbc" > <datasource type="jndi"> <property name="dbjndicontext" value="java:comp/env/jdbc/jpetstore"/> </datasource> </transactionmanager> 위설정은일반적인 JDBC 트랜잭션관리지만컨테이너가자원을관리한다. 당신은다음처럼전역 (global) 트랜잭션을설정하길원할수도있다. <transactionmanager type="jta" > <property name="usertransaction" value="java:/ctx/con/usertransaction"/> <datasource type="jndi"> 9

<property name="dbjndicontext" value="java:comp/env/jdbc/jpetstore"/> </datasource> </transactionmanager> UserTransaction 인스턴스가발견될수있는 JNDI 위치를가지키는 UserTransaction 값에주의하라. 좀더넓은범위의트랜잭션을가지는 SQL Maps 가다른데이터베이스와트랜잭션자원을포함하기위해서는 JTA 트랜잭션관리가요구된다. <sqlmap> 요소 sqlmap 요소는명시적으로 SQL Map 이나다른 SQL Map 설정파일을포함할때사용한다. SqlMapClient 인스턴스에의해사용되는각각의 SQL Map XML 파일은반드시선언되어야한다. SQL Map XML 파일은클래스패스나 URL 로부터스트림 (stream) 자원처럼로드될것이다. 당신은 SQL Maps 를명시해야한다. 다음은그에대한예이다. <!--CLASSPATH RESOURCES --> <sqlmap resource="com/ibatis/examples/sql/customer.xml" /> <sqlmap resource="com/ibatis/examples/sql/account.xml" /> <sqlmap resource="com/ibatis/examples/sql/product.xml" /> <!--URL RESOURCES --> <sqlmap url="file:///c:/config/customer.xml " /> <sqlmap url="file:///c:/config/account.xml " /> <sqlmap url="file:///c:/config/product.xml" /> 다음의다양한섹견은 SQL Map XML 파일들의구조에대해서서술한다. SQL Map XML 파일 ( http://ibatis.apache.org/dtd/sqlmap-config-2.dtd) 위예제에서우리는 SQL Maps 의가장간단한형태를보았다. SQL Map 문서구조내에사용가능한다른옵션이있다. 좀더많은기능을가지는 mapped statement 의예제이다. <sqlmap id= Product > </sqlmap> <cachemodel id= productcache type= LRU > <flushinterval hours= 24 /> <property name= size value= 1000 /> </cachemodel> <typealias alias= product type= com.ibatis.example.product /> <parametermap id= productparam class= product > <parameter property= id /> </parametermap> <resultmap id= productresult class= product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> </resultmap> <select id= getproduct parametermap= productparam resultmap= productresult cachemodel= product-cache > select * from PRODUCT where PRD_ID =? </select> 10

너무많은가.? 비록프레임워크가당신을위해많은것을하더라도간단한 select statement 를위해너무많은추가적인작업을하는것처럼보인다. 걱정하지마라다음은위의것의축소버전이다. <sqlmap id= Product > <select id= getproduct parameterclass= com.ibatis.example.product resultclass= com.ibatis.example.product > select PRD_ID as id, PRD_DESCRIPTION as description from PRODUCT where PRD_ID = #id# </select> </sqlmap> 지금 SQL Map 을행위적인측면에서보면이 statement 는정확하게같지는않다. 즉몇가지다른점을가진다. 먼저후자의 statement 는캐쉬를명시하지않아서매번의요청시데이터베이스에직접요청한다. 두번째후자의 statement 는약간의부하를야기할수있는프레임워크의자동맵핑기능을사용한다. 어쨌든두가지 statement 모두자바코드로부터정확하게같은방법으로작동하지않을것이다그리고당신은첫번째좀더간단한솔루션으로시작할것이고나중에는필요하면좀더향상된맵핑으로옮겨갈것이다. 가장간단한솔루션이많은경우에가장좋은연습이다. 하나의 SQL Map XML 파일은많은캐쉬모델, 파라미터맵핑, result 맵핑그리고 statement 를포함할수없다. 당신의애플리케이션을위해 statement 와 maps 를신중하게구성하라. 맵핑된 (Mapped) Statements SQL Maps 개념은맵핑된 statement 에집중한다. 맵핑된 statement 는어떠한 SQL 문을사용할수도있고파라미터 maps(input) 과 result maps(output) 를가질수있다. 만약간단한경우라면맵핑된 statement 는파라미터와 result 를위한클래스로직접설정할수있다. 맵핑된 statement 는메모리내에생산된 results 를캐슁하기위해캐쉬모델을사용하도록설정할수도있다. <statement id= statementname [parameterclass= some.class.name ] [resultclass= some.class.name ] [parametermap= nameofparametermap ] [resultmap= nameofresultmap ] [cachemodel= nameofcache ] > select * from PRODUCT where PRD_ID = [? #propertyname#] order by [$simpledynamic$] 위 statement 에서 [ 괄호 ] 부분은옵션이고몇몇의경우에만혼합할필요가있다. <statement id= inserttestproduct > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (1, Shih Tzu ) 위예제는명백하게발생할꺼같지는않다. 어쨌든이것은당신이임의의 SQL 문을실행하기위해 SQL Map 프레임워크를사용한다면유용할수있다. 어쨌든이것은파라미터 Maps 와 Result Maps 을사용하는자바빈즈맵핑기능을공통적으로사용할것이다. 다음의다양한섹션은구조와속성, 그들이어떻게맵핑된 statement 에영향을끼치는지서술한다. Statement 타입 <statement> 요소는어떤타입의 SQL 문을사용할수있는일반적인 catch all statement이다. 일반적으로이것은좀더다양한특성의 statement 요소중하나를사용하기위한좋은생각이다. 좀더다양한특성의요소는좀더직관적인 XML DTD를제공하고때때로일반적인 <statement> 요소가제공하지않는추가적인기능을제공한다. 다음의테이블은 statement요소 11

와그들이지원하는속성과기능을목록화한다. Statement 요소 속성 하위요소 메소드 <statement> id parameterclass resultclass parametermap resultmap cachemodel resultsettype fetchsize xmlresultname remapresults 모든동적요소 <insert> <update> <delete> <select> <procedure> The SQL id parameterclass parametermap id parameterclass parametermap id parameterclass parametermap id parameterclass resultclass parametermap resultmap cachemodel resultsettype fetchsize xmlresultname remapresults id parameterclass resultclass parametermap resultmap cachemodel xmlresultname remapresults 모든동적요소 <selectkey> 모든동적요소 모든동적요소 모든동적요소 모든동적요소 insert update delete 모든쿼리메소드 insert update delete insert update delete insert update delete 모든쿼리메소드 insert update delete 모든쿼리메소드 SQL 은 map 의가장중요한부분을차지한다. 이것은당신의데이터베이스와 JDBC 드라이버에적합한어떤 SQL 이될수있다. 당신은가능한어떤기능을사용할수있고당신의드라이버가지원하는한다중 statement 에전달할수도있다. 당신이하나의문서에서 SQL 과 XML 을혼합하기때문에특수문자의충돌이잠재적으로존재한다. 대부분의공통적인것은 greater-than 과 less-than 문자들이다.(<>). 이것들은 SQL 문에서공통적으로요구되고 XML 에서는예약어이다. 당신의 SQL 문에들어갈필요가있는특수 XML 문자를처리하기위한간단한해결법이있다. 표준적인 XML CDATA 섹션을사용함으로써특수문자의어떤것도파싱되지않고문제는해결된다. 예를들면 <statement id="getpersonsbyage" parameterclass= int resultclass="examples.domain.person"> <![CDATA[ SELECT * FROM PERSON WHERE AGE > #value# ]]> 12

자동생성키 많은관계형데이터베이스시스템은기본키 (primay key) 필드의자동생성을지원한다. 이 RDBMS 의기능은종종특정업체에종속된다. SQL Map 은 <insert> 요소의 <selectkey> 를통해자동생성키를지원한다. 선생성키 (pre-generated - 이를테면오라클 ) 과후생성키 (post-generated - 이를테면 MS-SQL 서버 ) 모두지원한다. 여기에그예제가있다. <! Oracle SEQUENCE Example --> <insert id="insertproduct-oracle" parameterclass="com.domain.product"> <selectkey resultclass="int"> SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL </selectkey> insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#) </insert> <! Microsoft SQL Server IDENTITY Column Example --> <insert id="insertproduct-ms-sql" parameterclass="com.domain.product"> insert into PRODUCT (PRD_DESCRIPTION) values (#description#) <selectkey resultclass="int"> SELECT @@IDENTITY AS ID </selectkey> </insert> 저장프로시저 저장프로시저는 <procedure> statement 요소를통해지원된다. 저장프로시저를출력물파라미터와함께어떻게사용하는지다음예제에서보여준다. <parametermap id="swapparameters" class="map" > <parameter property="email1" jdbctype="varchar" javatype="java.lang.string" mode="inout"/> <parameter property="email2" jdbctype="varchar" javatype="java.lang.string" mode="inout"/> </parametermap> <procedure id="swapemailaddresses" parametermap="swapparameters" > {call swap_email_address (?,?)} </procedure> 위처럼프로시저를호출하는것은파라미터객체 (map) 내에서두개의칼럼사이에두개의이메일주소를교체하는것이다. 파라미터객체는파라미터맵핑의 mode 속성값이 INOUT 또는 OUT 일경우에만변경된다. 다른경우라면변경되지않고남는다. 명백한불변의파라미터객체 ( 이를테면 String) 는변경할수없다. 주의! 언제나표준적인 JDBC 저장프로시저를사용하도록하라. 좀더다양한정보를보기위해서는 JDBC CallableStatement문서를보라. parameterclass parameterclass 속성값은자바클래스의전체경로를포함 ( 예를들면패키지를포함한 ) 한이름이다. parameterclass 속성은옵션이지만사용이굉장히추천되는것이다. 이것은프레임워크성능을향상시키는만큼 statement 에전달하는파라미터를제한하는데사용된다. 만약당신이 parametermap 을사용한다면 parameterclass 속성을사용할필요가없다. 예를들면당신이파라미터로전달하기위한 examples.domain.product 타입의객체를허락하길원한다면당신은다음처럼할수있을것이다. <statement id= statementname parameterclass= examples.domain.product > 13

insert into PRODUCT values (#id#, #description#, #price#) 중요 : 비록이전버전과의호환성을위한옵션이지만이것은언제나파라미터클래스를제공하는것은매우추천되는사항이다 ( 물론요구되는파라미터가없더라도 ). 프레임워크가먼저타입을안다면스스로최적화능력을가지기때문에당신은클래스를제공함으로써좀더나은성능을달성할수있다. 명시된 parameterclass 없이선호하는속성 (get/set메소드) 을가지는자바빈즈는파라미터를받을것이고어느위치에서매우유용하다. parametermap parametermap 속성값은명시된 ( 밑의경우처럼 ) parametermap 요소의이름이다. parametermap 속성은 parameterclass 속성과인라인파라미터의이익이되도록사용된다. XML 의깔끔함과일관성이당신의걱정이거나당신이좀더상세한 parametermap( 이를테면저장프로시저 ) 이필요하다면이것은좋은접근법이다. 주의! 동적으로맵핑된 statement 는단지인라인파라미터만지원하고파라미터 map 과는작동하지않는다. parametermap 의생각은 JDBC PreparedStatement 의값토큰과매치되는정렬된파라미터목록을명시한다. 예를들면 : <parametermap id= insert-product-param class= com.domain.product > <parameter property= id /> <parameter property= description /> </parametermap> <statement id= insertproduct parametermap= insert-product-param > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?); 위의예제에서, 파라미터 map 은 SQL 문에서값토큰 (? ) 에매치되고정렬되는두개의파라미터를서술한다. 그래서첫번째? 는 id 속성값에대체되고두번째는 description 속성값에대체된다. 파라미터 map 과그들의옵션은이문서나중에좀더다양하게서술될것이다. 인라인파라미터의빠른언급 이문서에나중에제공되는좀더상세화된설명에도불구하고인라인파라미터에대한빠른언급을한다. 인라인파라미터는맵핑된 statement 내부에서사용될수있다. 예를들면 : <statement id= insertproduct > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id#, #description#); 위예제에서인라인파라미터는 #id# 와 #description# 이다. 각각은 statement 파라미터를대체하는자바빈즈속성을표현한다. Product 클래스는포함된프라퍼티토큰이위치해있는 statement 내에위치하는값을위해읽게되는 id 와 description 프라퍼티을가진다. id=5 와 description= dog 를가지는 Product 를넘겨받은 statement 는다음처럼수행된다. insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (5, dog ); resultclass resultclass 속성값은자바클래스의전체경로를포함 ( 예를들면패키지를포함한 ) 한이름이다. resultclass 속성은우리에게 ResultSetMetaData 에기반한 JDBC ResultSet 에자동맵핑되는클래스를명시하도록한다. 자바빈즈의프라퍼티와 ResultSet의칼럼이매치될때마다프라퍼티는칼럼값과함께생성된다. 이것은매우짧고달콤하게맵핑된 statement 를쿼리한다. 예를 14

들면 : <statement id="getperson" parameterclass= int resultclass="examples.domain.person"> SELECT PER_ID as id, PER_FIRST_NAME as firstname, PER_LAST_NAME as lastname, PER_BIRTH_DATE as birthdate, PER_WEIGHT_KG as weightinkilograms, PER_HEIGHT_M as heightinmeters FROM PERSON WHERE PER_ID = #value# 위의예제에서 Person 클래스는 id, firstname, lastname, birthdate, weightinkilograms, heightinmeters 를포함하는프라퍼티를가진다. 칼럼별칭과함께대응되는각각은 SQL select 문에의해서술된다. 칼럼별칭은데이터베이스칼럼이름이매치되지않을때만요구된다. 일반적으로는요구되지않는다. 실행되었을때 Person 객체는프라퍼티이름과칼럼명에기반해서초기화되기위해맵핑되는 result set 으로부터초기화되고결과를반환한다. resultclass 으로자동맵핑하는데는몇가지제한점이있다. 출력칼럼의타입을명시하는방법은없다. 관련된데이터를자동적으로로드하는방법이없고 ResultSetMetaData 에접근하는데필요한접근법내에서하찮은성능결과가있다. 이제한점모드는명시적인 resultmap 를사용함으로써극복할수있다. Result maps 는이문서나중에좀더상세하게다루어질것이다. resultmap resultmap 프라퍼티는좀더공통적으로사용되고이해하기위해가장중요한속성중에하나이다. 이 resultmap속성값은명시된 resultmap 요소의이름이다. resultmap 속성을사용하는것은당신에게 result set 으로부터데이터와칼럼에맵핑되는프라퍼티를어떻게꺼내는지제어하도록한다. resultclass 속성을사용하는자동맵핑접근법과는달리 resultmap 는당신에게칼럼타입을명시하고 null 값을대체그리고복합프라퍼티맵핑 ( 다른자바빈즈, Collections 그리고원시타입래퍼 ) 을허락한다. resultmap 구조의모든상세정보는이문서나중에설명된다. 하지만다음의예제는 resultmap 가어떻게 statement 에관련되었는지보여준다. <resultmap id= get-product-result class= com.ibatis.example.product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> </resultmap> <statement id= getproduct resultmap= get-product-result > select * from PRODUCT 위예제에서 SQL 쿼리로부터 ResultSet 은 resultmap 정의를사용해서 Product 인스턴스에맵핑할것이다. resultmap 은 id 프라퍼티가 PRD_ID 칼럼과 PRD_DESCRIPTION 칼럼에의해생성되는 description 프라퍼티에의해생성될것이다. select * 를사용하는것은지원된다는것에주의하라. ResultSet 내반환칼럼모두에맵핑할필요는없다. cachemodel cachemodel 속성값은정의된 cachemodel 요소의이름이다. cachemodel 은쿼리가맵핑된 statement 를사용하기위한캐쉬를서술하는데사용된다. 각각의쿼리맵핑 statement 는다른 cachemodel 이나같은것을사용할수있다. cachemodel 요소와그것의속성에대한모든상세설명은나중에언급된다. 다음예제는어떻게 statement 와관련되는지보여준다. <cachemodel id="product-cache" imlementation="lru"> <flushinterval hours="24"/> <flushonexecute statement="insertproduct"/> <flushonexecute statement="updateproduct"/> <flushonexecute statement="deleteproduct"/> 15

<property name= size value= 1000 /> </cachemodel> <statement id= getproductlist parameterclass= int cachemodel= product-cache > select * from PRODUCT where PRD_CAT_ID = #value# 위예제에서캐쉬는 WEAK 참조타입을사용하는 products 를위해정의되고 24 시간마다또는관련된 update 문이수행될때마다지워진다 (flush). xmlresultname mapping result 를 XML 문서로직접적으로만들때 xmlresultname 의값은 XML 문서의가장상위요소의이름이될것이다. 예를들면 : <select id="getperson" parameterclass= int resultclass="xml" xmlresultname= person > SELECT PER_ID as id, PER_FIRST_NAME as firstname, PER_LAST_NAME as lastname, PER_BIRTH_DATE as birthdate, PER_WEIGHT_KG as weightinkilograms, PER_HEIGHT_M as heightinmeters FROM PERSON WHERE PER_ID = #value# </select> 위 select statement 는다음구조의 XML 객체를생성할것이다. <person> <id>1</id> <firstname>clinton</firstname> <lastname>begin</lastname> <birthdate>1900-01-01</birthdate> <weightinkilograms>89</weightinkilograms> <heightinmeters>1.77</heightinmeters> </person> remapresults remapresults 속성은 <statement>, <select>, 그리고 <procedure> 에서사용가능하다. 이것은선택적인속성이고디폴트는 false 이다. remapresults 속성은쿼리가반환칼럼의다양한세트를가질때 true 셋팅되어야만한다. 다음쿼리를보자. SELECT $fieldlist$ FROM table 이전예제에서칼럼의목록은테이블이언제나같더라도동적이다. SELECT * FROM $sometable$ 이전예제에서테이블은다를수있다. Select 절의 * 사용때문에, 결과적인칼럼이름은다를수있다. 동적요소는하나의쿼리수행에서다음수행까지변경하기위한목록을야기할수있다. resultset 메타데이타를알고 / 판단하기위한오버헤드가명백하지않기때문에, ibatis 는마지막쿼리수행에반환된것만을기억할것이다. 이것은위예제와비슷한상황에서문제를발생시킨다. 16

만약반환칼럼이변경된다면, remapresults 를 true 로셋팅하라. 그렇지않다면메타데이타검색의오버헤드를제거하기위해 remapresults 를 false 로셋팅하라. resultsettype SQL 구문의 resultsettype 을명시하기위해, 다음을사용할수있다. FORWARD_ONLY: 커서는앞쪽으로만이동한다. SCROLL_INSENSITIVE: 커서는스크롤가능하지만다른것에의한변경에는대개민감하지않다. SCROLL_SENSITIVE: 커서는스크롤가능하고다른것에의한변경에대개민감하다. resultsettype 은대개요구되지않는다. 그리고서로다른 JDBC 드라이버는같은 resultsettype 셋팅을사용하더라도다르게행동할것이다. ( 이를테면. Oracle 은 SCROLL_SENSITIVE 를지원하지않는다.). fetchsize SQL 구문의 fetchsize 를셋팅하는것은수행될것이다. 이것은 JDBC 드라이버에데이터베이스서버로의왕복을줄이기위해 prefetching 힌트를제공한다. 파라미터 Maps 와인라인파라미터 당신이위에서본것처럼 parametermap 는자바빈즈프라퍼티를 statement 의프라퍼티에맵핑시키는작업을수행한다. 비록 parametermaps 가외부형태내에드물게발생하더라도그것들이당신에게인라인파라미터를이해하도록도와준다는것을이해하라. <parametermap id= parametermapname [class= com.domain.product ]> <parameter property = propertyname [jdbctype= VARCHAR ] [javatype= string ] [nullvalue= NUMERIC ] [null= -9999999 ] [typename= {REF or user-defined type} /> <parameter /> <parameter /> </parametermap> [ 괄호 ] 내의부분은옵션이다. parametermap 는스스로는 statement 가그것을참조할때사용하는구분자로써단지 id속성만필요하다. Class 속성은옵션이지만크게사용이추천되는것이다. Statement 의 parameterclass 속성과유사하게 class속성은프레임워크가성능을위해엔진을최적화하는것만큼들어오는파라미터를체크하도록한다. <parameter> 요소 parametermap 은 statement 의파라미터에직접맵핑하는파라미터맵핑의어떤숫자를포함한다. 다음의일부섹션은 property 요소의속성을서술한다. property 파라미터 map 의 property 속성은맵핑된 statement 에전달되는파라미터객체의자바빈즈프라퍼티 (get메소드) 의이름이다. 그이름은 statement 내에필요한횟수에의존하는것보다좀더사용될수있다. jdbctype jdbctype속성은이프라퍼티에의해셋팅되는파라미터의칼럼타입을명시적으로정의하는데사용된다. 몇몇 JDBC드라이버는명시적인드라이버칼럼타입을부르는것없이어떤작동을위해칼럼의타입을확인할수없다. 이것의완벽한예제는 PreparedStatement.setNull(int parameterindex, int sqltype) 메소드이다. 이메소드는정의하기위한타입을요구한다. 몇몇드라이버는간단하게 Types.OTHER 또는 Types.NULL 을보냄으로써함축되는타입을허락한다. 어쨌든행위는비일관적이고몇몇드라이버는정의되기위한정확한타입을필요로한다. 그런경우를위해서 SQL Maps API 는 parametermap프라퍼티요소의 jdbctype 속성을사용하여정의되기위한타입을허락한다. 이속성은칼럼이 null 이가능할때 (nullable) 만요구된다. Type 속성을사용하는다른이유는명시적으로 date 타입을정의하 17

는것이다. 자바는단지하나의 Date값타입 (java.util.date) 을가지는데반해대개의 SQL 데이터베이스는많은, 대개최소 3가지이상의타입을가진다. 당신의칼럼타입이 DATE 나 DATETIME 중에하나로명시적으로정의하길바랄지도모르기때문이다. jdbctype 속성은 JDBC 타입클래스내변수와매치되는어떤문자열값에셋팅될수있다. 비록이것은그것들중에어떤것에셋팅될수있지만몇몇타입은지원되지않는다 ( 이를테면 blobs). 이문서의나중섹션에서프레임워크에의해지원되는타입에대해서서술한다. 주의! 대부분의드라이버는단지 null 이가능한칼럼을위해정의되는타입을필요로한다. 그러므로그런드라이버를위해당신은 null 이가능한칼럼을위해타입을정의할필요가있다. 주의! 오라클드라이버를사용할때당신은이것의타입을정의하지않고서는칼럼에 null 값을넣을때 Invalid column type 에러를보게될것이다. javatype javatype 속성은셋팅되기위한파라미터의자바프라퍼티를명시적으로정의하기위해사용된다. 대게이것은리플렉션 (reflection) 을통해자바빈즈프라퍼티로부터파생된다. 하지만 Map 과 XML 맵핑같은특정맵핑은프레임워크를위한타입을제공하지않는다. 만약 javatype 가셋팅되지않고프레임워크도어떤타입인지구별할수없다면타입은객체로간주될것이다. typename typename 속성은 REF 타입이나사용자정의타입을명시하기위해사용된다. javadoc 에보면.. typename 속성은사용자- 정의나 REF 출력파라미터를위해사용된다. 예를들면, 사용자- 정의타입은 STRUCT, DISTINCT, JAVA_OBJECT, 그리고명명된배열타입을포함한다. 사용자- 정의파라미터를위해, 파라미터의전체경로가포함된 SQL타입명이주어진다. 반면에 REF 파라미터는주어진참조타입의전체경로가포함된타입명을요구한다. JDBC 드라이버는타입코드를필요로하지않으며타입명정보는이것을무시한다. 이식가능하기위해, 애플리케이션은이러한사용자정의와 REF파라미터를위한값을제공해야만한다. 비록이것이사용자- 정의와 REF 파라미터가되더라도, 이속성은 JDBC 타입의파라미터를등록하기위해사용된다. 만약파라미터가사용자- 정의나 REF 타입을가지지않는다면, typename 파라미터를무시된다. nullvalue nullvalue 속성은어떤유효한값 ( 프라퍼티타입에기초로해서 ) 에셋팅할수있다. null 속성은 null 값대체를정의하기위해사용된다. 이것이의미하는것은자바빈즈프라퍼티내에서검색되는값인 NULL 이데이터베이스에쓰여질것이라는것이다 ( 들어오는 null 값대체의상반된행위 ). 이것은당신에게 null 값을지원하지않는타입 ( 이를테면 int, double, float등등 ) 을위해당신의애플리케이션내에 magic null 숫자를사용하도록허락한다. 프라퍼티의그런타입은적합한 null 값을포함할때 NULL은값대신에데이터베이스에쓰여질것이다. <parametermap> 예제 모든구조를사용하는 parametermap 의예제가다음과같다. <parametermap id= insert-product-param class= com.domain.product > <parameter property= id jdbctype= NUMERIC javatype= int nullvalue= -9999999 /> <parameter property= description jdbctype= VARCHAR nullvalue= NO_ENTRY /> </parametermap> <statement id= insertproduct parametermap= insert-product-param > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?); 위예제에서자바빈즈프라퍼티인 id 와 description 는목록화되는순서대로맵핑된 Statement 인 insertproduct 의파라미터에적용될것이다. 그래서 id 는첫번째파라미터 (?) 에적용되고 description 는두번째파라미터에적용된다. 만약에순서가반 18

대라면 XML 은다음처럼보일것이다. <parametermap id= insert-product-param class= com.domain.product > <parameter property= description /> <parameter property= id /> </parametermap> <statement id= insertproduct parametermap= insert-product-param > insert into PRODUCT (PRD_DESCRIPTION, PRD_ID) values (?,?); 주의! Parameter Map 이름은정의된 SQL Map XML 파일에위치한다. 당신은 SQL Map(<sqlMap> root 태그에셋팅된 ) 의 id와함께파라미터 Map 의 id 를앞에붙임으로써다른 SQL Map XML 파일내에파라미터 Map 을참조할수있다. 예를들면다른파일로부터위의파라미터 map 를참조하기위해참조하기위한전체이름은 Product.insert-product-param 이될것이다. 인라인파라미터 Maps 매우상세한설명에도불구하고 parametermaps 을선언하기위한위의문법은매우장황하다. 파라미터 Maps 을위한정의 (definition) 을간단하게하고코드를줄일수있는좀더다양한문법이있다. 그대안적인문법은자바빈즈프라퍼티이름을맵핑된 statement 에인라인시키는것이다. 초기설정에의해명시적으로정의된 parametermap 이없는어떤맵핑된 statement 는인라인파라미터를위해파싱될것이다. 이전의인라인파라미터를구현한예제 ( 이를테면 Product) 는다음처럼보일것이다. <statement id= insertproduct parameterclass= com.domain.product > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id#, #description#); 타입을선언하는것은다음의문법을사용함으로써인라인파라미터로할수있다. <statement id= insertproduct parameterclass= com.domain.product > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id:numeric#, #description:varchar#); 타입을선언하는것과 null 값대체는다음문법을사용함으로써인라인파라미터로할수있다. <statement id= insertproduct parameterclass= com.domain.product > insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id:numeric:-999999#, #description:varchar:no_entry#); 주의! 인라인파라미터를사용할때당신은타입정의없이 null 값대체를명시할수없다. 당신은순서대로파싱하기위해둘다명시해야한다. 주의! Null 값의완전한투명성을원한다면당신은이문서의나중에설명되는것처럼당신의 result maps 내에 null 값대체를반드시명시해야한다. 주의! 당신이많은수의타입서술자와 null 값대체가필요하다면당신은외부적인것을사용해서코드를정리할수있어야할것이다. 원시타입파라미터 파라미터처럼사용하기위해자바빈을쓰는것은언제나필요하고편리한것은아니다. 이런경우에당신은직접적으로파라미터를사용하는것처럼원시타입래퍼객체 (String, Integer, Date 등등 ) 를사용하는것을환영할것이다. 예를들면 : 19

<statement id= insertproduct parameter= java.lang.integer > select * from PRODUCT where PRD_ID = #value# PRD_ID 가숫자타입이라고가정하자. 호출이되었을때 java.lang.integer 객체를전달할수있는맵핑된 statement 를만들것이다. #value# 파라미터는 Integer 인스턴스의값으로대체될것이다. value 라는이름은간단한문법 ( 이를테면괄호 ) 안의요소이고별명이될수있다. Result Map 는 result 처럼원시타입을잘지원한다. 파라미터로원시타입을사용하는방법에대해서좀더다양한정보를위해서는 Result Map 섹션과프로그래밍 SQL Maps(API) 를보라. 원시타입은좀더간결한코드를위해서별칭된다. 예를들면 int 는 java.lang.integer 대신에사용될수있다. 별칭은아래의 파라미터 Map 과 result Map 을위해지원되는타입 이라는제목의테이블에서이야기된다. Map 타입파라미터당신이자바빈즈클래스를쓰는것이필요하지않거나편리하지않은위치에있고하나의원시타입파라미터을쓰지는않는다면파라미터객체로 Map( 이를테면 HashMap, TreeMap) 을사용할수있다. 예를들면 : <statement id= insertproduct parameterclass= java.util.map > select * from PRODUCT where PRD_CAT_ID = #catid# and PRD_CODE = #code# 맵핑된 statement 구현내에서는차이점이없다는것을알라. 위의예제에서만약 Map 인스턴스가 statement 를위한호출로전달되었다면 Map 은 catid 과 code 라는이름의키를포함해야만한다. 이값은 Integer 과 String 과같은선호되는타입이되는그런키에의해참조된다. Result Map 은 result 처럼 Map 타입을아주잘지원한다. 파라미터처럼 Map 타입을사용하는것에대한좀더상세한정보를위해서는 result Map 섹션과프로그래밍 SQL Map(API) 를보라. Map 타입역시좀더간결한코드를위해별칭된다. 예를들면 map 는 java.util.map 을대신할수있다. 별칭은아래의 파라미터 Map 과 result Map 을위해지원되는타입 이라는제목의테이블에서이야기된다. Result Maps Result maps 는 SQL Maps 의가장중요한컴포넌트이다. resultmap 는자바빈즈프라퍼티를맵핑된쿼리 statement를실행함으로써생산된 ResultSet 의칼럼에맵핑시키는책임을진다. resultmap 의구조는다음과같이보인다. <resultmap id= resultmapname class= some.domain.class [extends= parent-resultmap ]> <result property= propertyname column= COLUMN_NAME [columnindex= 1 ] [javatype= int ] [jdbctype= NUMERIC ] [nullvalue= -999999 ] [select= someotherstatement ] /> <result /> <result /> <result /> </resultmap> [ 괄호 ] 부분은옵션이다. resultmap 는스스로 statement 가그것을참조하기위해사용할 id 속성을가진다. resultmap 는클래스나타입별칭의전체경로를포함한이름인 class 속성을가진다. 이클래스는이것을포함하는 result 맵핑에기반하여초기화되고생성될것이다. Extends속성은 resultmap 에기초한다른 resultmap 의이름을옵션적으로셋팅할수있다. 이것은상위 resultmap 의모든프라퍼티가하위 resultmap 의부분을포함하는것처럼자바내에서클래스를확장하는것과유사하다. 상위 resultmap 의프라퍼티는하위 resultmap 프라퍼티와부모 resultmap 가자식앞에서정의되기전에언제나추가된다. 상위 / 하위 resultmap 를위한클래스는같은것을필요로하지않을뿐아니라모든것이관련될필요도없다. resultmap 은자바빈즈를 ResultSet 의칼럼에맵핑시키는어느정도의프라퍼티맵핑을포함할수있다. 그런프라퍼티맵핑은문서내에서정의하기위해적용될것이다. 관련클래스는각각의프라퍼티, Map 또는 XML 을위한 get/set 메소드를가진자바빈즈와호환되는클래스여야만한다. 20

주의! 칼럼은 Result Map 내에서정의되기위해서명시적으로읽을것이다. 다음의섹션은 property 요소의속성들을서술한다. property result map 의 property 속성은맵핑 statement 에의해반환되는 result 객체의자바빈즈프라퍼티 (get메소드) 이름이다. 이름은 results 를생성할때필요한횟수에의존적인값보다더크게사용될수있다. column column 속성값은프라퍼티를생성하기위해사용될값들로부터의 ResultSet 내의칼럼의이름이다. columnindex 옵션적인 ( 최소한의 ) 성능향상을위해서 columnindex 속성값은자바빈즈프라퍼티를생성하기위해사용될값으로부터의 ResultSet 내의칼럼의인덱스이다. 이것은애플리케이션의 99% 정도엔필요하지않을것이고유지를위한노력과속도를위해가독성을희생한다. 몇몇 JDBC 드라이버는다른것들이동적으로속도를올려주는동안어떤성능이득도구체화하지않을것이다. jdbctype jdbctype 속성은자바빈즈프라퍼티를생성하는데사용되는 ResultSet 칼럼의데이터베이스칼럼타입을명시적으로정의하는데사용된다. 비록 result maps 이 null 값과함께같은어려움을가지지않는다고하더라도 Date 프라퍼티처럼어떤맵핑타입을위해유용할수있는타입을정의한다. 자바는오직하나의 Date 값타입을가지고 SQL 데이터베이스는여러가지를가지기때문에 dates( 또는다른타입 ) 타입을정확하게셋팅하는것을확신하는몇몇경우에필요하게될것이다. 유사하게도 String 타입은 VARCHAR, CHAR 또는 CLOB 에의해생성될것이다. 그래서그런경우에필요한타입을정의하라. javatype javatype 속성은셋팅되는프라퍼티의자바프라퍼티타입을명시적으로정의하기위해사용된다. 대개이것은리플렉션 (reflection) 을통해자바빈즈프라퍼티로부터끌어낼수있다. 하지만 Map 와 XML 맵핑과같은맵핑은프레임워크를위한타입을제공할수없다. 만약 javatype 가셋팅되지않고프레임워크가그타입을구분할수없다면타입은객체로가정되어처리될것이다. nullvalue nullvalue 속성은데이터베이스내에서 NULL 값을대신해서사용되기위한값을정의한다. 그래서만약 ResultSet으로부터 NULL 이읽었다면자바빈프라퍼티는 NULL 대신에 nullvalue 속성에의해정의된값을셋팅할것이다. null 속성값은어떠한값을될수있지만프라퍼티타입을위해서는적절해야만한다. 만약당신의데이터베이스가 NULL 이가능한칼럼을가진다면당신은당신의애플리케이션이다음처럼 result map내에서그것을정의할수있는변수값과함께 NULL 을표시하기를원한다. <resultmap id= get-product-result class= com.ibatis.example.product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> <result property= subcode column= PRD_SUB_CODE nullvalue= -999 /> </resultmap> 위예제에서만약 PRD_SUB_CODE 이 NULL 로읽혀진다면 subcode 프라퍼티는 -999 라는값으로셋팅될것이다. 이것은당신에게데이터베이스내에서 NULL 이가능한칼럼을표현하기위해당신의자바클래스내에원시타입을사용하도록허락할것이다. 만약당신이 updates/inserts 같은쿼리를위한작업을수행하기를원할때당신은파라미터 map 내에 nullvalue 를정의해 21

야만한다는것을기억해라. select select 속성은객체사이의관계를서술하고자동적으로복합프라퍼티타입을로드하는데사용된다. statement프라퍼티값은다른맵핑된 statement 의이름이되어야만한다. 데이터베이스칼럼값은 statement 속성이파라미터처럼관계된맵핑 statement 로전달하는것처럼같은 property 요소내에정의된다. 그러므로칼럼은원시타입으로지원이되어야한다. 지원되는원시타입과복합프라퍼티맵핑 / 관계에대한상세정보는이문서나중에이야기된다. 내포하는 Result Maps 만약당신이명시적으로정의된 resultmap 의재사용을요구하지않는다는매우간단한요구사항을가진다면맵핑된 statement 의 resultclass 속성을셋팅함으로써 result map 을함축적으로정의하는빠른방법이있다. 이묘기는당신이반환되는 result set 이당신의자바빈의쓰기가능한프라퍼티이름에매치되는칼럼이름 ( 또는라벨 / 별칭 ) 을가지는것을확실해야만한다는것이다. 예를들면만약우리가위에서서술된 Product 클래스를생각할때우리는다음처럼내포하는 result map으로맵핑된 statement 를생성할수있다. <statement id= getproduct resultclass= com.ibatis.example.product > select PRD_ID as id, PRD_DESCRIPTION as description from PRODUCT where PRD_ID = #value# 위의맵핑된 statement 는 resultclass 를표기하고 Product 클래스의자바빈즈프라퍼티에매치되는각각의칼럼를위한별칭을명시한다. 이것은모두필수 (required) 이다. Result map 은필요하지않다. 여기서교환 (tradeoff) 은당신이칼럼타입 ( 대개필수가아닌 ) 과 null값 ( 또는다른어떤프라퍼티속성 ) 을정의하는기회를가지지않는것이다. 많은데이터베이스가대소문자를가리지않기때문에내포된 result map 는또한가리지않는다. 만약당신의자바빈이두개의프라퍼티를가진다면하나의이름은 firstname 이고다른것은 firstname이다 ( 두개의값은대소문자의차이이다 ). 그것들은동일하고당신은내포된 result map 를사용할수없을것이다 ( 이것은자바빈클래스의디자인에서잠재적인문제점을파악하게될것이다.). 게다가 resultclass 를통해자동맵핑을하면몇몇성능에관련된부하가발생할것이다. ResultSetMetaData 에접근하는것은몇몇쓰여진 JDBC 드라이버로는느리게만들수있다. 원시타입의 Results ( 이를테면 String, Integer, Boolean) 자바빈호환클래스를지원하기위해추가적으로 result Map 은 String, Integer, Boolean 등등과같은간단한자바타입래퍼를편리하게생성할수있다. 원시타입객체의 collection 은밑에서이야기되는 API(executeQueryForList() 를보라 ) 들을사용해서가져올수있다. 원시타입은자바빈처럼같은방법으로정확하게맵핑된다. 원시타입은당신이선호하는 ( 대개 value 또는 val ) 이름형식의어떤것처럼될수있는하나의프라퍼티만을가질수있다. 예를들면우리가전체 Product 클래스대신에모든 product서술자 (description) 의목록만을로드하길원한다면 map 은다음처럼보여질것이다. <resultmap id= get-product-result class= java.lang.string > <result property= value column= PRD_DESCRIPTION /> </resultmap> 좀더간단한접근법은맵핑된 statement 안에서간단하게 result class 를사용하는것이다.( as 키워드를사용해서 value 라는칼럼별칭을사용하는것을주의깊게보라.) <statement id= getproductcount resultclass= java.lang.integer > select count(1) as value from PRODUCT 22

Map Results Result Maps 은 HashMap 또는 TreeMap 처럼 Map 인스턴스를편리하게생성할수있다. 그런객체 (Map 의 List) 의 collection은아래에서이야기되는 API(executeQueryForList() 를보라 ) 들을사용해서가져올수있다. Map 타입은자바빈과같은방법으로정확하게맵핑된다. 하지만자바빈프라퍼티셋팅대신에 Map 의 key 들은대응되는맵핑칼럼을위한값을참조하도록셋팅한다. 예를들면만약우리가 product 의값을 Map 으로빨리로드시키길원한다면우리는다음처럼할것이다. <resultmap id= get-product-result class= java.util.hashmap > <result property= id column= PRD_ID /> <result property= code column= PRD_CODE /> <result property= description column= PRD_DESCRIPTION /> <result property= suggestedprice column= PRD_SUGGESTED_PRICE /> </resultmap> 위예제에서 HashMap 인스턴스는 Product 데이터를생성할것이다. 프라퍼티이름속성 ( 이를테면 id ) 은 HashMap 의키가될것이다. 맵핑칼럼의값은 HashMap 의값이될것이다. 물론당신은 Map 타입을가지고내포된 result map 을사용할수도있다. 예를들면 : <statement id= getproductcount resultclass= java.util.hashmap > select * from PRODUCT 위의것은반환된 ResultSet 의 Map 표현을당신에게줄것이다. 복합 (Complex) Properties ( 이를테면사용자에의해정의된클래스의프라퍼티 ) 이것은선호하는데이터와클래스를로드하는방법을알고있는맵핑된 statement 와함께관련된 resultmap 프라퍼티에의해복합타입의프라퍼티 ( 사용자에의해생성된클래스 ) 를자동적으로생성하는것은가능하다. 데이터베이스내데이터는언제나복합프라퍼티는관계의 many side 로부터이고프라퍼티자신은관계의 one side 로부터이다라는것을고정하는클래스에서 1:1 관계또는 1:M 관계를통해표현된다. 예를들면 : <resultmap id= get-product-result class= com.ibatis.example.product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> <result property= category column= PRD_CAT_ID select= getcategory /> </resultmap> <resultmap id= get-category-result class= com.ibatis.example.category > <result property= id column= CAT_ID /> <result property= description column= CAT_DESCRIPTION /> </resultmap> <statement id= getproduct parameterclass= int resultmap= get-product-result > select * from PRODUCT where PRD_ID = #value# <statement id= getcategory parameterclass= int resultmap= get-category-result > select * from CATEGORY where CAT_ID = #value# 위예제에서 Product 의인스턴스는 Category 타입의 category 를호출하는프라퍼티를가진다. Category 는복합사용자타입이기때문에 JDBC 는그것을생성하는방법을가지지않는다. 프라퍼티맵핑과함께다른맵핑된 statement 를관련시킴으로써우리는그것을생성하기위한 SQL Map 엔진을위해충분한정보를제공한다. getproduct 를수행하면 get-product-result result map 이 PRD_CAT_ID 칼럼내반환되는값을사용해서 getcategory 을호출할것이다. get-category-result result map 은 Category 를초기화할것이고그것을생성한다. 전체 Category 인스턴스는 Product 의 category 프라퍼티로셋팅한다. N+1 Selects (1:1) 피하기 23

위솔루션을사용할때문제점은당신이 Product 를로드할때마다두개 (Product 를위해하나그리고 Category 를위해서하나. 총 2개 ) 의 SQL 문이실제적으로구동된다는것이다. 이문제는하나의 Product 를로드할때는큰문제가아닌것처럼보이지만만약 10 개의 Product 를로드하는쿼리를한다면각각의쿼리는관련된 category 를로드하기위한 Product 를위해서도실행될것이다. 결과적으로 11 번의쿼리를하게된다. Product 의목록을위해하나, 관련된 Category 를로드하기위해반환되는 Product 를위해하나씩 (N+1 또는이경우엔 10+1=11) 해결법은분리된 select 문대신에조인과내포된 (nested) 프라퍼티맵핑을사용하는것이다. 여기에그와같은상황을사용한예제가있다. <resultmap id= get-product-result class= com.ibatis.example.product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> <result property= category.id column= CAT_ID /> <result property= category.description column= CAT_DESCRIPTION /> </resultmap> <statement id= getproduct parameterclass= int resultmap= get-product-result > select * from PRODUCT, CATEGORY where PRD_CAT_ID=CAT_ID and PRD_ID = #value# 늦은 (Lazy) 로딩대조인 (1:1) 조인을사용하는것이언제나더좋은결과를내지는않는다는것에주의하는것은중요하다. 만약당신이관계객체에접근하는것이거의없는상황이라면조인을피하는것이더빠르고모든 category 프라퍼티의로딩이불필요하다. 이것은 outer 조인을포함하는데이터베이스디자인이나 null 값이가능하거나인덱스가없는칼럼에는사실이다. 이런상황에서늦은로딩과 bytecode 향상옵션으로 sub-select 솔류선을사용하는것은좀더향상된결과를보여준다. 일반적인규칙은연관된프라퍼티에접근하는것을좀더하고자할때만조인을사용하라. 반면에늦은로딩이옵션이아닐때에만그것을사용하라. 만약당신이사용할방법을결정하는데문제가있다면걱정하지마라. 그것은문제도아니다. 당신은자바코드충돌없이이것을항상변경할수있다. 위의두예제는같은객체형태의결과를보이고정확하게같은메소드호출을사용해서로드된다. 만약당신이캐쉬를가능하게하면단지하나의고려사항은 separate select( 조인이아닌 ) 솔루션을사용하는것이반환되는캐쉬된인스턴스내에결과를보이게된다. 복합 Collection 프라퍼티 복합객체의목록을표현하는프라퍼티를로드하는것은가능하다. 데이터베이스내의데이터는 M:M 관계나 1:M 관계에의해표현될것이다. 객체목록을로드하는것은 statement 에어떤변경사항도주지않는다. SQL Map 프레임워크가비즈니스객체내에서리스트처럼프라퍼티를로드하기위해요구되는단하나의차이점은 java.util.list 또는 java.util.collection 타입이되어야한다는것이다. 예를들면 Category 가 Product 인스턴스목록을가진다면맵핑은다음처럼보일것이다.(Category가 java.util.list 타입의 productlist 라고불리는프라퍼티를가진다고가정하자.) <resultmap id= get-category-result class= com.ibatis.example.category > <result property= id column= CAT_ID /> <result property= description column= CAT_DESCRIPTION /> <result property= productlist column= CAT_ID select= getproductsbycatid /> </resultmap> <resultmap id= get-product-result class= com.ibatis.example.product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> </resultmap> <statement id= getcategory parameterclass= int resultmap= get-category-result > select * from CATEGORY where CAT_ID = #value# <statement id= getproductsbycatid parameterclass= int resultmap= get-product-result > select * from PRODUCT where PRD_CAT_ID = #value# 24

N+1 Selects (1:M 과 M:N) 피하기 이것은위의 1:1 상황과유사하다. 하지만굉장히많은데이터를포함할때좀더큰걱정거리가될것이다. 위해결법과함께문제는당신이 Category 를로드할때마다두개의 SQL문 ( 하나는 Category 를위한하나이고하나는 Products 에대한목록을위한것 ) 은실질적으로수행된다. 이문제는하나의 Category 를로드할때평범한것처럼보이지만 10 개의 Category 를로드하는쿼리문을실행할때는각각의쿼리가 Product 의목록을로드하기위한각각의 Category 를위해서수행될것이다. 결과적으로 11 개의쿼리가수행된다. 하나는 Category 목록을위한것이고각각의 Product 관련목록을반환하는각각의 Category를위한것이다 (N+1 또는이경우엔 10+1=11). 이상환을더욱나쁘게만들려면우리는굉장히많은데이터를다루면된다. 1:N 과 M:N 해결법 ibatis 는이문제를해결한다. 다음은그예제이다. <sqlmap namespace="productcategory"> <resultmap id= categoryresult class= com.ibatis.example.category groupby= id > <result property= id column= CAT_ID /> <result property= description column= CAT_DESCRIPTION /> <result property= productlist resultmap= ProductCategory.productResult /> </resultmap> <resultmap id= productresult class= com.ibatis.example.product > <result property= id column= PRD_ID /> <result property= description column= PRD_DESCRIPTION /> </resultmap> <select id= getcategory parameterclass= int resultmap= categoryresult > select C.CAT_ID, C.CAT_DESCRIPTION, P.PRD_ID, P.PRD_DESCRIPTION from CATEGORY C left outer join PRODUCT P on C.CAT_ID = P.PRD_CAT_ID where CAT_ID = #value# </select> </sqlmap> 당신이호출할때, List mylist = executequeryforlist("productcategory.getcategory", new Integer(1002));... 메인쿼리는수행되고결과는 com.ibatis.example.category 타입의 bean 인 mylist 변수에저장된다. List 내각각의객체는같은쿼리로부터생성되는 List 인 productlist 프라퍼티를가질것이다. 하지만하위목록내 bean 을생성하는 productresult 결과맵을사용한다. 그래서당신은하위목록을포함하는목록으로종료하고오직하나의데이터베이스쿼리만이수행된다. 가장중요한항목은 "categoryresult" 결과맵내 groupby="id"... 속성이고... <result property="productlist" resultmap="productcategory.productresult"/>... 프라퍼티맵핑이다. 다른중요한사항은 productlist 프라퍼티를위한결과맵핑이명명공간을인식 ( 이것은작동하지않는 productresult 이될것이다.) 하는것이다. 이접근법을사용하여, 당신은 N+1 문제를풀수있다. 25

늦은 (Lazy) 로딩대조인 (1:M and M:N) 먼저이야기된 1:1 상황처럼조인을사용하는것이언제나더좋다는것이아니라는것을아는것은중요하다. 이것은대량의데이터로인하여개별적인값프라퍼티를위한것보다 collection 프라퍼티에서좀더사실적이다. 만약당신이관련된객체에접근하는것이드문상황 ( 이를테면 Category 클래스의 productlist 프라퍼티 ) 이라면이것은조인과 product 목록의필요없는로딩을피한다면정말빠르게될것이다. 이것은 outer 조인과 null 이가능하고아니면또는인덱스가없는칼럼을포함한데이터베이스디자인에는특별히사실이다. 이런상황에서늦은 (lazy) 로딩과 bytecode 향상옵션으로 sub-select 솔루션을사용하는것은좀더향상시켜준다. 일반적인규칙은연관된프라퍼티에접근하는것을좀더하고자할때만조인을사용하라. 반면에늦은로딩이옵션이아닐때에만그것을사용하라. 먼저언급했던것처럼만약당신이어떤방법을사용해야하는지결정하는데문제가있다면걱정하지마라. 어떤방법을사용할지에대해서걱정하는것은필요없는일이다. 당신은당신의자바코드에충돌없이그것을변화시킬수있다. 위의두예제는같은객체형태의결과를보이고정확하게같은메소드호출을사용해서로드된다. 만약당신이캐쉬를가능하게하면단지하나의고려사항은 separate select( 조인이아닌 ) 솔루션을사용하는것이반환되는캐쉬된인스턴스내에결과를보이게된다. 복합키또는다중복합파라미터프라퍼티 당신은위예제에서 column 속성에의해 resultmap 내에정의된것처럼사용되어지는것은하나의키라는것이언급되었다. 이것은단지하나의키만이관계된맵핑 statement 에관련될수있다는것을제안했다. 어쨌든관계된맵핑 statement 에전달할다중칼럼을허락하는대안적인문법이있다. 이것은복합키관계가존재하는상황이나당신이간단하게 #value# 와다른이름의파라미터를사용하고자할때편리하다. Column 속성이간단 {param1=column1, param2=column2,, paramn=columnn} 할때대안적인문법이다. PAYMENT 테이블이 Customer ID 와 Order ID 를둘다키로할때다음의예제를보고생각해보라. <resultmap id= get-order-result class= com.ibatis.example.order > <result property= id column= ORD_ID /> <result property= customerid column= ORD_CST_ID /> <result property= payments column= {itemid=ord_id, custid=ord_cst_id} select= getorderpayments /> </resultmap> <statement id= getorderpayments resultmap= get-payment-result > select * from PAYMENT where PAY_ORD_ID = #itemid# and PAY_CST_ID = #custid# 옵션적으로당신은그것들이파라미터처럼같은순서로정렬되는것처럼칼럼이름을정의할수있다. 예를들면 {ORD_ID, ORD_CST_ID} 언제나처럼이것은읽기와유지라는것의영향과함께미세한성능획득이있다. 중요! 현재의 SQL Map 프레임워크는순환하는관계를자동으로해석하지않는다. 부모 / 자식관계 ( 트리 ) 를구현할때이것을알고있어라. 쉬운대안은간단하게부모객체를로드하기않는경우를위한하나또는 N+1 avoidance 해결법에서서술된조인을사용하는경우를위한두번째 result map 를정의하는것이다. 주의! 몇몇 JDBC드라이버 ( 이를테면내장된 PointBase) 는동시에다중 ResultSet(connection마다 ) 을지원하지않는다. 그런드라이버는 SQL Map 엔진이다중 ResultSet connection 을요구하기않기때문에복잡한객체맵핑과는작동하지않을것이다. 다시말해조인을사용하는거대신에이것을해석할수있다. 주의! Result Map 이름은언제나그것들이정의된 SQL Map XML 파일에위치한다. 당신은 SQL Map 의이름을 Result map 의이름앞에위치시킴으로써다른 SQL Map XML 파일내의 Result Map 를참조할수있다. 26

만약당신이 JDBC 를위해 MS 의 SQL Server2000 드라이버를사용한다면당신은수동트랜잭션모드인동안다중 statement 를수행하기위해 connection url 에 SelectMethod=Cursor 을추가할필요가있을지도모른다.(MS 의지식기반기사 313181을보라. http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b313181). 파라미터 Maps 와 Result Maps 를위해지원되는타입들 파라미터와 result 를위해 ibatis 프레임워크에의해지원되는자바타입은다음과같다. Java Type JavaBean/Map Property Mapping Result Class / Parameter Class*** Type Alias** boolean YES NO boolean java.lang.boolean YES YES boolean byte YES NO byte java.lang.byte YES YES byte short YES NO short java.lang.short YES YES short int YES NO int/integer java.lang.integer YES YES int/integer long YES NO long java.lang.long YES YES long float YES NO float java.lang.float YES YES float double YES NO double java.lang.double YES YES double java.lang.string YES YES string java.util.date YES YES date java.math.bigdecimal YES YES decimal * java.sql.date YES YES N/A * java.sql.time YES YES N/A * java.sql.timestamp YES YES N/A * java.sql. date 타입사용은좋지않다 (discouraged). 대신에 java.util.date 를사용하는것이제일좋다. **. 파라미터나 result 클래스를정의할때타입별칭은전체경로의클래스명에두는것이좋다. *** int, boolean and float 와같은원시타입은 ibatis 데이터베이스레이어가완전한객체지향접근법을사용하는것처럼직접적으로원시타입을지원하지는않는다. 그러므로모든파라미터와 result 는그들의상위레벨에서객체가되어야한다. 부수적으로 JDK1.5 의 autoboxing 기능은잘사용되기위해원시타입을허락한다. 사용자정의타입핸들러생성하기 타입은 TypeHandlerCallback 인터페이스의사용을통해 ibatis 내에서확장될수있다. 당신자신의타입핸들러를생성하기위해, TypeHandlerCallback 을구현한클래스를생성할필요가있다. 사용자정의타입핸들러를사용하여당신은지원되지않는타입을다루거나지원되는타입을다른방법으로다뤄서프레임워크를확장할수있다. 예륻들면, 당신은적절한 BLOB지원을구현하는사용자정의타입핸들러를사용하거나대개 0/1 대신에 Y 와 N 을사용하는 boolean 을다루기위해이것을사용할수있다. 다음은 Yes 와 No 를사용하는 boolean 핸들러의간단한예제이다. public class YesNoBoolTypeHandlerCallback implements TypeHandlerCallback { private static final String YES = "Y"; private static final String NO = "N"; public Object getresult(resultgetter getter) 27

throws SQLException { String s = getter.getstring(); if (YES.equalsIgnoreCase(s)) { return new Boolean (true); } else if (NO.equalsIgnoreCase(s)) { return new Boolean (false); } else { throw new SQLException ( "Unexpected value " + s + " found where " + YES + " or " + NO + " was expected."); } } public void setparameter(parametersetter setter, Object parameter) throws SQLException { boolean b = ((Boolean)parameter).booleanValue(); if (b) { setter.setstring(yes); } else { setter.setstring(no); } } public Object valueof(string s) { if (YES.equalsIgnoreCase(s)) { return new Boolean (true); } else if (NO.equalsIgnoreCase(s)) { return new Boolean (false); } else { throw new SQLException ( "Unexpected value " + s + " found where " + YES + " or " + NO + " was expected."); } } ibatis 내사용하기위한이러한타입을선언하기위해, 당신은 sqlmapconfig.xml 내다음의문법을사용한다. <typehandler javatype="boolean" jdbctype= VARCHAR callback="org.apache.ibatis.sqlmap.extensions.yesnobooltypehandlercallback"/> ibatis 가 java 타입과 jdbc 타입간의이전을다루는것을알고난뒤에, 특정타입핸들러콜백은작성된다. 캐쉬상태의맵핑된 Statement Results 맵핑된 statement 쿼리로부터의 result 는 statement 태크내에 cachemodel 파라미터를정의함으로써간단하게캐쉬될수있다. 캐쉬모델은당신의 SQL Map 내에서정의된설정된캐쉬다. 캐쉬모델은다음처럼 cachemodel 요소를사용해서설정된다. <cachemodel id="product-cache" type ="LRU" readonly= true serialize= false > <flushinterval hours="24"/> <flushonexecute statement="insertproduct"/> <flushonexecute statement="updateproduct"/> <flushonexecute statement="deleteproduct"/> <property name= cache-size value= 1000 /> </cachemodel> 28

위의캐쉬모델은 LRU(Least Recently Used) 방식을사용해서 product-cache 라는이름의캐쉬인스턴스를생성할것이다. type 속성값은전체경로의클래스명이거나아래처럼구현을포함하는것의별칭이다. flush 요소에기초로하여캐쉬모델내에서정의된다. 이캐쉬는 24 시간마다삭제된다. interval 요소내에서 hours, minutes, seconds 또는 milliseconds 단위로설정이되어서삭제된다. 캐쉬는추가적으로 insertproduct, updateproduct, 또는deleteProduct 맵핑 statement 가수행될때마다삭제된다. 캐쉬를위해 flush on execute 요소의숫자값이정의될수있다. 몇몇캐쉬구현물은위에서보여지는 cache-size 같은추가적인프라퍼티를필요로한다. LRU 캐쉬의경우에크기는캐쉬내저장되기위한항목의갯수로결정된다. 캐쉬모델이설정되었을때당신은맵핑된 statement 에의해사용되기위한캐쉬모델을정의할수있다. 예를들면 <statement id= getproductlist cachemodel= product-cache > select * from PRODUCT where PRD_CAT_ID = #value# 읽기전용대읽기 / 쓰기 프레임워크는읽기전용과읽기 / 쓰기캐쉬를모두지원한다. 읽기전용캐쉬는모든유저에의해공유되어서좀더큰성능향상을보여준다. 어쨌든읽기전용캐쉬로부터읽어들인객체는변경할수없다. 대신에새로운객체는업데이트를위해데이터베이스 ( 또는읽기 / 쓰기캐쉬 ) 로부터읽어야만한다. 반면에정정 (retrieval) 및변경을위한객체를사용할경우에는읽기 / 쓰기캐쉬가추천된다 ( 이를테면필수이다 ). 읽기전용캐쉬를사용하기위해서는캐쉬모델요소에 readonly= true 를셋팅하라. 기초설정값은읽기전용 (true) 이다. 직렬화가능한읽기 / 쓰기캐쉬 당신이동의한다면서술된것처럼세션당캐쉬는전역애플리케이션성능에자그마한이익을준다. 읽기 / 쓰기캐쉬의다른타입은전체애플리케이션이직렬화가능한읽기 / 쓰기캐쉬라면성능향상을보여준다. 이캐쉬는각각의세션에캐쉬된객체의다른인스턴스를반환할것이다. 그러므로각각의세션은안전하게반환된인스턴스를변경할수있다. 여기서의미론적인차이점을알아보자면당신은언제나캐쉬로부터반환된같은인스턴스를기대하겠지만캐쉬내에서당신은다른것을얻게될것이다. 또한직렬화가능한캐쉬로부터저장된모든객체는직렬화가능해야만한다. 이것은직렬화가능한캐쉬로조합된늦은 (lazy) 로딩기능을사용하기에는어려울것이라는것을의미한다. 왜냐하면늦은 (lazy) 프록시는직렬화가능하지않기때문이다. 캐쉬의조합을해결하는가장좋은방법은늦은 (lazy) 로딩과테이블조인을간단히시도하는것이다. 직렬화가능한캐쉬를사용하기위해서는기초설정캐쉬모델이읽기전용이고직렬화가능하지않기때문에 readonly= false 와 serialize= true 로셋팅하라. 읽기전용캐쉬는직렬화되지않을것이다. 캐쉬타입들 캐쉬모델은다른타입의캐쉬를지원하기위해서플러그인형태의프레임워크를사용한다. 그구현은 cachemodel요소의 type 속성값내에정의된다. 이정의된클래스이름은 CacheController 인터페이스의구현이나아래에서논의되는 4 가지별칭중에하나가되어야만한다. 게다가설정파라미터는 cachemodel 내에포함된 property 요소를통해구현체로전달될수있다. 현재배포판에는 4 가지구현물을포함하고있다. 그들은다음과같다. MEMORY (com.ibatis.db.sqlmap.cache.memory.memorycachecontroller) MEMORY 캐쉬는캐쉬행위를관리하기위해서참조타입을사용한다. 그것은가비지컬렉터 (garbage collector) 가캐쉬내에머물러있는지아닌지효과적으로결정한다. MEMORY 캐쉬는객체재사용의일정한패턴이없는애플리케이션또는메모리가충분하지않은애플리케이션을위한좋은선택이다. MEMORY 구현은다음처럼설정된다. <cachemodel id="product-cache" type="memory"> <flushinterval hours="24"/> <flushonexecute statement="insertproduct"/> <flushonexecute statement="updateproduct"/> <flushonexecute statement="deleteproduct"/> <property name= reference-type value= WEAK /> </cachemodel> 단지하나의프라퍼티가 MEMORY 캐쉬구현에의해인식된다. reference-type 라는이름의프라퍼티는 STRONG, SOFT 또는 29

WEAK 의값으로셋팅되어야만한다. 그값들은 JVM 내에유효한여러가지메모리참조타입에대응된다. 다음의테이블은 MEMORY 캐쉬를위해사용될수있는다른참조타입을서술한다. 참조타입을핵심을좀더이해하기위해서는 reachability 에대한정보를위한 java.lang.ref 부분의 JDK 문서를보기를바란다. SOFT 닥나는가능성을제거할것이다. 어쨌든이것은할당되고좀더중요한객체에유효하지않는메모리에대해대부분공격적인참조타입이아니다. STRONG 이참조타입은명시적을캐쉬가삭제될때까지메모리내에저장된결과물을보증한다. 이것은 1) 매우작음, 2) 절대적으로정적, and 3) 매우종종사용되는결과에좋다. 장점은특수한쿼리를위해매우좋은성능을보인다. 단점은결과물에의해사용되는메모리가필요할때다른객체를위해메모리를반환하지않는다. LRU (com.ibatis.db.sqlmap.cache.lru.lrucachecontroller) LRU 캐쉬는객체가자동으로캐시로부터어떻게삭제되는지결정하기위해 Least Recently Used( 가장최근에적게사용된 ) 알고리즘을사용한다. 캐쉬가가득찼을때가장최근에접근된객체는캐쉬로부터삭제된다. 이방법은종종참조되는특수한객체가있을때이것은가장최근에삭제된변경과함께캐쉬내에남을것이다. LRU 캐쉬는오랜시간동안하나이상의사용자에게특별한객체가사용되는패턴을가지는애플리케이션을위해서좋은선택이다 ( 이를테면페이지처리된목록사이에앞페이지뒷페이지를탐색하는, 특수한검색키.. 등등 ). LRU 구현은다음처럼설정된다. <cachemodel id="product-cache" type="lru"> <flushinterval hours="24"/> <flushonexecute statement="insertproduct"/> <flushonexecute statement="updateproduct"/> <flushonexecute statement="deleteproduct"/> <property name= size value= 1000 /> </cachemodel> 단지하나의프라퍼티만이 LRU 캐쉬에의해인식된다. size 라는이름의프라퍼티는한번에캐쉬내에고정되는객체의최대갯수를표현하는숫자값으로설정해야한다. 여기서기억해야할중요한것은하나의문자열인스턴스로부터자바빈즈의 ArrayList 해당되는어떠한객체로도될수있다는것이다. 그래서메모리포화의위험이있다면당신의캐쉬내너무많이저장하지마라. FIFO (com.ibatis.db.sqlmap.cache.fifo.fifocachecontroller) FIFO 캐쉬는객체가캐쉬로부터자동적으로어떻게삭제될지결정하기위해 First In First Out( 먼저들어온것을먼저보낸다.) 알로리즘을사용한다. 캐쉬가가득찼을때가장오래된객체는캐쉬로부터삭제될것이다. FIFO 캐쉬는특수한쿼리가빠른성공내에서적은수로참조되는패턴을사용할때좋다. 하지만나중에몇몇시점에서는가능하지않다. FIFO 구현은다음처럼설정된다. <cachemodel id="product-cache" type="fifo"> <flushinterval hours="24"/> <flushonexecute statement="insertproduct"/> <flushonexecute statement="updateproduct"/> <flushonexecute statement="deleteproduct"/> <property name= size value= 1000 /> </cachemodel> 단지하나의프라퍼티가 FIFO 캐쉬에의해인식된다.. size 라는이름의프라퍼티는한번에캐쉬내에고정되는객체의최대갯수를표현하는숫자값으로설정해야한다. 여기서기억해야할중요한것은하나의문자열인스턴스로부터자바빈즈의 30