[iBatis] queryWithRowHandler 메소드를 사용한 RowHandler사용하기

Published on: 2013. 12. 18. 15:15 by louis.dev

iBatis는 DB쿼리문의 결과를 Java Object로 매핑시켜주는 Persistent Layer의 Framework로서 DB쿼리로 검색된 결과를 다양한 자바 오브젝트( Custom Object, List, Map 등)로 생성, 매핑 시켜주어 DB 쿼리 결과를 자바단에서 쉽게 사용할수 있도록 해줍니다.


그러나 수행한 쿼리의 Row수가 대량일 경우 iBatis는 문제를 일으키게 됩니다.


예를 들어 특정 쿼리로 검색된 row의 수가 천만건이 된다고 하면, iBatis는 해당 쿼리 결과를 자바 오브젝트에 매핑 시키기 위해 사이즈가 천만인 ArrayList 인스턴스를 생성하게 될것입니다. 그렇게 대량의 자바 인스턴스를 생성하게 되면 JVM에서 사용하는 메모리사이즈를 초과하게 되어 결국 Out of Memory Exception를 뿜으며 시스템이 뻗어버리게 됩니다.


위와 같이 대량의 데이터를 셀렉트 해오는 경우에는 RowHandler를 사용하여 Out Of Memory Exception을 피해갈수 있습니다.


RowHandler를 생성하는 방법은 com.ibatis.sqlmap.client.event.RowHandler 인터페이스를 impliments 하면 됩니다.

public class TestRowHandlerCallback implements RowHandler {
	@Override
	public void handleRow(Object arg0) {
		TestClass class = (TestClass) arg0;
		//TODO select된 row 하나하나가 Java Object로 생성되어 넘어온다.
	}
}

이렇게 만들어진 RowHandler는 SqlMapClient를 사용할때 queryWithRowHandler라는 메소드를 사용하여 RowHandler를 사용하도록 지정하면 됩니다.

TestRowHandlerCallback callback = new TestRowHandlerCallback();
//getSqlMapClientTemplate().queryWithRowHandler("Test.rowHandlerTestQuery", callback);		//스프링 사용시
getSqlMapClient().queryWithRowHandler("Test.rowHandlerTestQuery", callback);

이렇게 queryWithRowHandler 메소드로 RowHandler를 지정하게 되면 iBatis는 List 인스턴스를 생성하지 않고 Row당 하나의 자바 오브젝트를 생성한 후 RowHandler의 handleRow 메소드를 실행시킵니다. 


이렇게 되면 아무리 많은 row가 검색되었다고 하더라도 List Object를 생성하지 않기 때문에 Out Of Memory Exception이 발생하지 않게 되어 안전하게 개발할 수 있습니다.






iBatis - queryForMap을 사용하여 map 인스턴스 return 받기

Published on: 2010. 12. 13. 17:34 by louis.dev

흔히 iBatis를 사용하면 SqlMapClient의 queryForListqueryForObject를 많이 사용하게 됩니다.
queryForList는 select문을 통하여 여러 row를 가져올때 iBatis가 List형태로 리턴해 주고, queryForObject는 select의 where조건을 통해 하나의 row만 가져오게 됩니다.
하지만 SqlMapClient에는 이들 메소드 만큼 유용한 메소드를 지원해 주는데, 그 메소드가 바로 queryForMap입니다. SqlMapClient의 queryForMap은 select문을 통해 검색된 데이터를 map형태로 리턴해 주는 아주 유용한 메소드 입니다.

Map형태로 데이터를 가져올때 약 2가지의 방법이 있습니다.

1. column을 key로 데이터를 value로 가질때
만약 select query를 통해 검색된 데이터가 다음과 같다고 가정하겠습니다.

ex)select * from test_tb where idx = 1
 idx  name  title  contents  read_count
 1  전근재  이건뭔가요?  아..모르겠다..ㅜㅜ  100

다음과 같이 검색 되었다고 할때 key값으로는 column(idx,name, title, contents, read_count)이고 각 값들은 검색된 값(1, 전근재, 이건뭔가요?, 아 모르겠다..ㅜㅜ, 100)으로 하고 싶으면 다음과 같이 작업하면 됩니다.

<SPAN id=tx_marker_caret><?xml version="1.0" encoding="UTF-8" ?>
<sqlMap namespace="tutorial">
     <resultMap id="tutorialMap" class="java.util.HashMap">
          <result column="idx" property="idx"/>
          <result column="name" property="name"/>
          <result column="title" property="title"/>
          <result column="contents" property="contents"/>
          <result column="read_count" property="readCount" javaType="int"/>
     </resultMap>

     <select id="getBoardItem" parameterClass="int" resultMap="tutorialMap">
          SELECT *
          FROM test_tb
          WHERE idx = #idx#
     </select>
</sqlMap></SPAN>


위와 같이 설정한후 queryForObject객체로 데이터를 가져 오면 됩니다.
ex)return (Map<String,Object>) getSqlMapClient().queryForObject( "tutorial.getBoardItem", idx);

위의 result의 property속성이 map의 key가 됩니다. 즉 return을 통해 map을 받았으면, map.get("read_count") 가 아니라 map.get("readCount")로 데이터를 가져옵니다.

또한 resultMap의 read_count에는 javaType으로 int형이 선언되어 있는데, 만약 이렇게 지정하지 않으면, iBatis가 숫자형을 BigDecimal로 지정하여 나중에 타입형변환을 하면 문제를 일으킵니다.(BigDecimal은 int형으로 형변환 할수 없다.. 뭐 이렇게 나오죠... 이거때문에 많이 삽질했습니다..ㅜㅜ)


2. 특정 column의 데이터를 key로 또 다른 특정 column을 value로 지정 할때
다음과 같은 select query가 있다고 하겠습니다.

ex) select name, ssn from test_tb;
 name  ssn
 태연  111111-2222222
 김태희  222222-3333333
 이민정  333333-4444444
로 데이터가 검색 되었다고 가정 하겠습니다.

만약 name의 값들을 key로 사용하고 ssn의 값들을 value로 사용하려고 하면, queryForMap을 사용하면 됩니다.
<?xml version="1.0" encoding="UTF-8" ?>
<sqlMap namespace="tutorial">
     <select id="getUserMap" resultClass="java.util.HashMap">
          SELECT name,ssn
          FROM test_tb
     </select>
</sqlMap>

위와 같이 select문을 구성합니다.
그리고 dao에서 SqlmapClient 인스턴스의 queryForMap 메소드를 이용하여 map을 return 받습니다.

ex) return (Map) getSqlMapClient.queryForMap("tutorial.getUserMap", null, "name", "ssn");
이라고 하면 됩니다.
null은 query 문으로 전달할 파라미터가 없음으로 null을 넣은 것이고, 널 다음의 인자가 key를 나타내는 column, 그 다음인자가 value를 나타내는 column 명을 입력하시면 됩니다.

만약 이때 이 key, value의 column명이 AS를 통해 다른이름으로 붙여 졌다면, 해당이름으로 queryForMap을 call해야 합니다.
ex) SELECT name AS n, ssn AS s FROM test_tb
라면 queryForMap("tutorial.getUserMap", null, "n", "s"); 로 실행해야 제대로 데이터를 받을 수 있습니다.

이렇게 queryForMap으로 데이터를 받으면, 해당 map에서 map.get("김태희") 는 222222-3333333 이 나올 것입니다.


자주는 아니지만 map형식으로 받을 일이 종종 있기 때문에 알아두면 다 피가되고 살이되는 정보 입니다~^^

iBatis - 기본 설정 & 게시판 만들기

Published on: 2010. 10. 26. 19:51 by louis.dev

IBatisTutorial.war



얼마전 iBatis 프로젝트가 myBatis라는 이름으로 변경되면서 apache 사이트에서 code.google로 이동하였습니다. myBatis 프로젝트로 변경되면서 많은 설정 부분이 변경되었지만, 일단 많이 사용하는 iBatis2 버전을 가지고 진행 하겠습니다.

본 설정법은 Eclipse + Tomcat 6.0 그리고 MySql 5 버전을 통해 진행하도록 하겠습니다.

iBatis란?
iBatis는 DBMS와 Java 객체간의 자동 맵핑 프레임웍 입니다.
즉, iBatis에서 select 쿼리를 수행하여 검색 된 쿼리가 다음과 같고
 idx  category  title  regDate  readCount
 1  질문  질문합니다.  2010-10-26  0

자바 객체의 property 명이 검색된 쿼리문의 column의 이름과 같다면
package net.tutorial.ibatis.vo;

import java.util.Date;

public class IbatisBoardVO {
	private int idx;
	private String category;
	private String title;
	private String contents;
	private Date regDate;
	private int readCount;
	private String writer;
}

각각의 검색된 column 명에따라 자동으로 객체에 저장이 됩니다.

이렇듯 iBatis는 쉽게 DB의 데이터를 제어할 수 있는 DBMS-JAVA 객체간의 맵핑 프레임웍입니다.

iBatis 설정방법
1. iBatis 라이브러리와 MySQL Connector 라이브러리 다운
자바 프로그래밍의 시작은 늘 라이브러리의 추가입니다~^^

iBatis-2.3.4.726 을 다운로드 후, lib안의 ibatis-2.3.4.726.jar 
MySQL Java용 Connector 다운로드 후, mysql-connectgor-java-5.1.13-bin.jar
위의 두 파일을 이클립스에서 생성한 웹프로젝트 안의 webContent\WEB-INF\lib 디렉토리에 추가합니다.

2. 게시판에 사용될 DB와 Table을 생성합니다.(콘솔에서 접근하여 DB를 생성해도 되고, 다른 어플리케이션을 통해서 테이블을 생성하셔도 상관없습니다. 전 개인적으로 SQLGate라는 프로그램을 사용해서 개발합니다.^^)

MySQL DB생성과 권한 설정 방법

-DB 생성 쿼리
CREATE DATABASE board_db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

-Table 생성 쿼리
CREATE TABLE `ibatis_board_tb` (
  `idx` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `category` char(30) DEFAULT NULL,
  `title` text,
  `contents` text,
  `reg_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `read_count` int(10) DEFAULT NULL,
  `writer` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`idx`),
  UNIQUE KEY `idx` (`idx`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

위와 같은 스크립트로 board_db 라는 데이터 베이스와 ibatis_board_tb 라는 테이블을 생성했습니다.

3. 생성된 테이블과 맵핑될 Value Object를 생성해 줍니다.
- IbatisBoardVO
package net.tutorial.ibatis.vo;

import java.util.Date;

public class IbatisBoardVO {
	private int idx;
	private String category;
	private String title;
	private String contents;
	private Date regDate;
	private int readCount;
	private String writer;
	public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContents() {
		return contents;
	}
	public void setContents(String contents) {
		this.contents = contents;
	}
	public Date getRegDate() {
		return regDate;
	}
	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}
	public int getReadCount() {
		return readCount;
	}
	public void setReadCount(int readCount) {
		this.readCount = readCount;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("IbatisBoardVO [category=");
		builder.append(category);
		builder.append(", contents=");
		builder.append(contents);
		builder.append(", idx=");
		builder.append(idx);
		builder.append(", readCount=");
		builder.append(readCount);
		builder.append(", regDate=");
		builder.append(regDate);
		builder.append(", title=");
		builder.append(title);
		builder.append(", writer=");
		builder.append(writer);
		builder.append("]");
		return builder.toString();
	}
}


4. DB를 사용할때 필요한 설정파일을 생성합니다.
1) db.properties
이 파일은 DB Connection을 맺기 위한 driver, url, username, password 등을 저장하는 파일입니다.
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/생성한DB이름?characterEncoding=utf-8
username=DB에접근아이디
password=DB접근패스워드


2) iBatis 설정을 할 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">
<sqlMapConfig>
	<!-- 하단의 DataSource 설정을 위해 위에서 생성한 db.properties 파일 위치 설정 -->
	<properties resource="net/tutorial/ibatis/sqlmap/db.properties" />
	<!-- 
		iBatis사용을 위한 설정입니다. 아래 설정내용은 
		useStatementNamespaces="false"를 true로 변경한것 빼고는 Default 설정입니다.
	-->
	<settings
		cacheModelsEnabled="true"
		enhancementEnabled="true"
		lazyLoadingEnabled="true"
		maxRequests="32"
		maxSessions="10"
		maxTransactions="5"
		useStatementNamespaces="true"
	/>
	<!-- properties태그로 properties 파일 위치 경로를 선언하면 
	     ${properties파일에 선언한 이름} 으로 접근하여 데이터를 가져 올수 있습니다.
	     properties 파일을 생성하지 않고 ${driver} 대신 바로 "com.mysql.jdbc.Driver"
	     와 같이 직접 넣을 수도 있습니다.
	-->
	<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}"/>
		</dataSource>
	</transactionManager>
	
	<!--sqlMap 태그는 실제 쿼리문이 들어갈 xml파일입니다. -->
	<sqlMap resource="net/tutorial/ibatis/sqlmap/BoardSqlMap.xml" />
</sqlMapConfig>


3) 사용할 쿼리문을 정의할 BoardSqlMap.xml 파일을 생성합니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
 		        "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<!--
 	SqlMapConfig.xml 파일에서 namespace사용을 true로 변경하였기 때문에 이 XML의 네임스페이스를 
 	IbatisBoard로 정의합니다.
-->
<sqlMap namespace="IbatisBoard">
	<!--
		typeAlias태그는 type에 선언된 클래스 파일을 짧은이름으로 치환해 주는 역할을 합니다.
		즉 net....IbatisBoardVO란 java파일을 이 xml에서는 Board란 이름으로 사용하겠다는 뜻입니다
	-->
	<typeAlias alias="Board" type="net.tutorial.ibatis.vo.IbatisBoardVO"/>
	
	<!-- 
		실제 사용할 쿼리 문입니다.
		select 시에는 select,
		delete 시에는 delete
		update 시에는 update 태그를 사용하여 쿼리문을 생성합니다.
		이때 id는 필수 요소 입니다. 이 아이디를 통해 쿼리문을 접근할 수 있습니다.
		resultClass="Board" 는 아래 쿼리문을 통해 select된 데이터를 Board 클래스에 자동으로 저장하겠다는 뜻이고, 이 Board클래스는 상단의 typeAlias를 통해 alias시킨 것임으로 결국 IbatisBoardVO에 자동으로 저장될 것입니다.
		 
	-->
	<select id="getTotalBoardList" resultClass="Board">
		SELECT
			idx, category, title, reg_date AS regDate, read_count AS readCount, writer
		FROM
			ibatis_board_tb
		ORDER BY idx DESC
	</select>
</sqlMap>


4) iBatis를 사용하기 위한 자바 객체인 SqlMapClient를 생성하는 SQLManager class를 생성합니다.
package net.tutorial.ibatis.manager;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import java.io.IOException;

public abstract class SQLManager{
	private SqlMapClient sc;

    public SQLManager(){
        sc = null;
        try{
            sc = SqlMapClientBuilder.buildSqlMapClient(Resources.getResourceAsReader("net/tutorial/ibatis/sqlmap/SqlMapConfig.xml"));
        }
        catch(IOException ie){
            ie.printStackTrace();
        }
    }

    public SqlMapClient getSqlMap(){
        return sc;
    }

}


SQLMapClient객체는 SqlMapConfig.xml파일을 읽어서 생성하게 되고, getSqlMap method를 통해 SqlMapClient객체를 전달 하게 됩니다.
이 클래스는 DB접근을 위한 클래스인 DAO(Data Access Object)에서 상속받아 사용하면됩니다.

여기까지 iBatis 사용을 위한 설정이 끝났습니다. 이제 이 설정을 통해 iBatis사용 하도록 해보겠습니다.
저는 html테그를 사용할 jsp - 비지니스로직을 처리할 service class - iBatis를 사용해서 DB에 접근하기 위한 DAO class를 만들어 MVC패턴으로 진행하도록 하겠습니다.

5. SQLManager를 상속받은 DAO class를 생성합니다.
package net.tutorial.ibatis.dao;

import java.sql.SQLException;
import java.util.List;

import net.tutorial.ibatis.manager.SQLManager;
import net.tutorial.ibatis.vo.IbatisBoardVO;

public class IbatisBoardDAO extends SQLManager {
	@SuppressWarnings("unchecked")
	public List<IbatisBoardVO> getTotalBoardList(){
		try {
			return getSqlMap().queryForList("IbatisBoard.getTotalBoardList");
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}
}


getTotalBoardList란 method는 select Query를 통해 게시판 테이블의 내용을 모두 가져와 List형태로 리턴해 주는 method입니다.
이부분에서 중요하게 봐야 할부분은 두군대 인데요

첫번째. SQLManager를 상속받고 getSqlMap method로 SqlMapClient 객체를 가져옵니다.
이때 SqlMapClient객체를 통해 호출 할수 있는 method는 여러가지가 있는데 5가지 정도만 살펴보겠습니다.(제일 많이 사용하는 method이기도 합니다)
① queryForList : Select를 통해 데이터를 가져올때 사용합니다. 만약 Select를 통해 얻어오는 데이터가 여러 행일경우, iBatis는 자동으로 List형태로 변환하여 전달해 줍니다.
② queryForObject : Select를 통해 데이터를 가져올때 사용합니다. 만약 select를 통해 얻어오는 데이터가 1개일 경우(where 조건문을 통해서) queryForObject 를 사용합니다.
③ insert : insert를 할때 사용합니다.
④ update : update를 할때 사용합니다.
⑤ delete : delete를 할때 사용합니다.

두번째. queryForList메소드(queryForObject, insert, update, delete 모두 동일)의 파라미터로 IbatisBoard.getTotalBoardList 로 전달하는데 앞의 IbatisBoard는 BoardSqlMap.xml의 namespace이고, 뒤의 getTotalBoardList는 BoardSqlMap.xml의 select태그 ID입니다.
이렇게 하면 IbatisBoard 라는 네임스페이스를 갖는 xml에서 getTotalBoardList라는 아이디를 갖는 쿼리를 실행하겠단 뜻이 됩니다.

6. 비지니스 로직을 처리할 Service class인 IbatisBoardServlce class를 생성합니다.
package net.tutorial.ibatis.service;

import java.util.List;

import net.tutorial.ibatis.dao.IbatisBoardDAO;
import net.tutorial.ibatis.vo.IbatisBoardVO;

public class IbatisBoardService {
	private IbatisBoardDAO ibatisBoardDAO = new IbatisBoardDAO();
	
	public List<IbatisBoardVO> getTotalBoardList() {
		return ibatisBoardDAO.getTotalBoardList();
	}
}

크게 로직을 처리하는 부분은 아직까지 없음으로 결과값만 return해 주는 역할만 하겠습니다.

7. 데이터를 보여줄 웹페이지(board_list.jsp)를 만들겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@page import="java.util.List"%>
<%@page import="net.tutorial.ibatis.vo.IbatisBoardVO"%>
<%@page import="net.tutorial.ibatis.service.IbatisBoardService"%>
<%
	IbatisBoardService boardService = new IbatisBoardService();
	List<IbatisBoardVO> boardList = boardService.getTotalBoardList();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IBatis 게시판 tutorial</title>
</head>
<body>
	<table border="1" cellpadding="0" cellspacing="0" width="800" align="center">
		<tr>
			<td>글번호</td>
			<td>카테고리</td>
			<td>제목</td>
			<td>작성자</td>
			<td>등록일</td>
			<td>조회수</td>
		</tr>
		<% for(IbatisBoardVO board : boardList ) { %>
		<tr>
			<td><%=board.getIdx() %></td>
			<td><%=board.getCategory() %></td>
			<td><%=board.getTitle() %></td>
			<td><%=board.getWriter() %></td>
			<td><%=board.getRegDate() %></td>
			<td><%=board.getReadCount() %></td>
		</tr>	
		<%} %>
	</table>
</body>
</html>


위와 같이 작업하시면 결과 페이지를 확인 하실수 있습니다. 단. DB에 글 데이터는 들어있어야 겠죠~?^^

iBatis - iterate 태그로 동적 Query를 생성해 보자

Published on: 2010. 10. 6. 13:44 by louis.dev
Query문 중 가끔 동적으로 어떠한 쿼리를 생성해야 할 경우가 있습니다.. 
예를 들면 어떠한 리스트에 있는 값을 통해 쿼리문을 생성한다던지 하는 경우 iBatis에서는 iterate 태그로 for문과 같은 역할을 하여 동적 쿼리를 생성 할 수 있습니다.

<select id="getData" parameterClass="java.util.List" resultClass="int">
	SELECT
		count(0)
	FROM data_tb
	<iterate prepend="WHERE id IN" open="(" close=")" conjunction="," >
        	#[]#
     	</iterate>
</select>

위와 같이 parameterClass를 java의 List형태로 전달해 주면 동적쿼리를 생성할수 있습니다. 만약 list에 1,2,3,4 의 데이터가 들어가 있으면 결과적으로
다음과 같은 쿼리가 실행되는 것과 같습니다.
<select id="getData" parameterClass="java.util.List" resultClass="int">
	SELECT
		count(0)
	FROM data_tb
	WHERE id IN (1,2,3,4)
</select>
이렇게  iterate를 사용하여 동적으로 쿼리문을 생성할 수 있습니다.

또한 parameterClass가 list형태가 아닌 Map이 List를 가지고 있는 형태도 iterate의 property 속성을 통해 접근할 수 있습니다.
만약 HashMap에 paramList라는 이름으로 list형이 들어가 있다고 가정하면
예)
 HashMap<String, Object> paramMap = new HashMap<String, Object>();
List<Integer> paramList = new ArrayList<Integer>();
paramMap.put("paramList", paramList);
<select id="getData" parameterClass="HashMap" resultMap="myResult">
	SELECT
		*
	FROM data_tb
	<iterate property="paramList" prepend="WHERE id IN" open="(" close=")" conjunction="," >
                #paramList[]#
     	</iterate>
 </select>

위와 같이 HashMap에 들어있는 list는 iterate의 property 속성을 통해 List를 가져 옵니다. ##사이는 HashMap에 put했던 list이름을 넣어주셔야 작동합니다.

iBatis - 기본 설정

Published on: 2009. 6. 25. 16:42 by louis.dev


1. iBatis Library를 추가한다.

2. 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">

<sqlMapConfig>
    <settings
  cacheModelsEnabled="true"
  enhancementEnabled="true"
  lazyLoadingEnabled="true"
  maxRequests="32"
  maxSessions="10"
  maxTransactions="5"
  useStatementNamespaces="false"
 />
 
<!-- JNDI사용 -->
   <transactionManager type="JDBC" >
 <dataSource type="JNDI">
   <property name="DataSource"
      value="java:comp/env/jdbc/XE"/>
 </dataSource>
   </transactionManager>
 <sqlMap resource="com/myhome/info/sql/SqlMap.xml" />
</sqlMapConfig>

/////////////////////////////////////////////////////////////////
위의 설정은 JNDI를 사용하기 때문에 JNDI설정을 해 주어야 한다.

1. Server 의 server.xml파일에 다음을 추가한다.
(33번째 줄 <GlobalNamingResources> 태그 안에 선언한다)

<Resource auth="Container"
        driverClassName="oracle.jdbc.driver.OracleDriver"
        factory="org.apache.commons.dbcp.BasicDataSourceFactory"
        maxActive="20"
        maxIdle="10" 
        maxWait="-1"
        name="jdbc/XE"
        username="user01"
        password="user01"
        type="javax.sql.DataSource"
        url="jdbc:oracle:thin:@localhost:1521:XE" />

2. Server 의 context.xml 파일의 가장 하단에 다음을 추가 한다.

<ResourceLink global="jdbc/XE"
                  name="jdbc/XE"
                  type="javax.sql.DataSource"/>


※JNDI말고 다른 방법으로 사용 할 수 있다. SqlMapConfig.xml 파일에 다음을 추가 한다.
1.simple datasource type  사용
<transactionManager type="JDBC" commitRequired="false">
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver"
                      value="oracle.jdbc.driver.OracleDriver"/>
            <property name="JDBC.ConnectionURL"
                      value="jdbc:oracle:thin:@localhost:1521:XE"/>
            <property name="JDBC.Username" value="user01"/>
            <property name="JDBC.Password" value="user01"/>
        </dataSource>
    </transactionManager>

2.DBCP datasource type 사용
<properties resource=" info/model/dao/db.properties " />
     
   <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"/>
  </dataSource>
  </transactionManager> 
////////////////////////////////////////////////////////////////

3.SqlMap.xml 파일을 생성 한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
 "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap>
  <typeAlias alias="Info" type="com.myhome.info.dto.InfoDTO"/><!-- alias : 별칭을 잡겠다는 의미 -->
 
  <insert id="infoInsert" parameterClass="Info"><!-- typeAlias한 Info를 넣는다 없으면 com.. 그대로 넣어도 된다. -->
   INSERT INTO INFO
    (NUM, NAME, SEX, TEL, WDATE)
   VALUES
    (NUMSEQ.NEXTVAL, #name#, #sex#, #tel#, #wdate#)<!-- ## Info 안에 가지는 프로퍼티 대소문자가 정확하게 맞아야 한다. -->
  </insert>
 
  <statement id="infoList" resultClass="Info">
   SELECT NUM, NAME, SEX, TEL, WDATE
   FROM INFO
  </statement>
 
</sqlMap>

4.SQLManager.java 파일 생성
package com.myhome.manager;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public abstract class SQLManager {
 
 private SqlMapClient sc = null;
 
 public SQLManager(){
  try{
   sc = SqlMapClientBuilder.buildSqlMapClient(
            Resources.getResourceAsReader(
              "com/myhome/info/sql/SqlMapConfig.xml"));
  }catch(java.io.IOException ie){
   ie.printStackTrace();
  }
 }
 
 public SqlMapClient getSqlMap(){
  return sc;
     }
}

5.DAO에서 다음과 같이 사용
package com.myhome.info.dao;

import com.myhome.info.dto.InfoDTO;
import com.myhome.manager.SQLManager;
import java.sql.SQLException;
import java.util.List;

public class InfoDAO extends SQLManager{
 /*등록부분*/
 public void register(InfoDTO dto) throws SQLException{
  this.getSqlMap().insert("infoInsert",dto);
 }
 
 /*회원 리스트 부분*/
 @SuppressWarnings("unchecked")
 public List<InfoDTO> getAllQuery(){
  List<InfoDTO> list = null;
  try {
   list = (List<InfoDTO>)this.getSqlMap().queryForList("infoList");
  } catch (SQLException e) {
   e.printStackTrace();
  }
  return list;
 }
}


☆SqlMapConfig.xml의 추가 사항

1.전체적인 내용
 
<?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">

<sqlMapConfig>

    <settings/>

    <properties resource=" db.properties " />

    <transactionManager></transactionManager>

    <sqlMap></sqlMap>

</sqlMapConfig>

위에서 가장 중요한 것은 transactionManager 와 sqlMap부분이며 setting과 properties resource 는 선택 사항이다.

2. settings의 내용들
cacheModelsEnalbe ="true" : SqlMapClient를 위한 모든 캐쉬모델을 가능하게 하거나 가능하지 않게 한다.
이것은 디버깅시 도움이 된다.
enhancernetEnable="true" : 향상된 lazy로딩처럼 최적화된 자바빈즈 속성 접근을 위해 런타임시 바이트코드 향상을 가능하게 한다.
lazyLoadingEnabled="true" : SqlMapClient 를 위한 모든 lazy로딩ㅇ르 가능하게 하거나 가능하지 않게 한다.
maxRequests="32" : 한꺼번에 SQL을 실행할 스래드 수이고 2에n승으로 확장할 수 있고 128이 맥시멈이다.
maxSession="10" : 주어진 시간동안 활성화 될 수 있는 세션 수
maxTransaction="5" : 한꺼번에 SqlMapClient.startTransaction()에 들어갈 수 있는 스레드의 최대 갯수
useStatementNamespaces ="false"
 

3. db.properties 파일 설정
 


driver=oracle.jdbc.driver.OracleDriver


url=jdbc:oracle:thin:@localhost:1521:XE


username=user01

password=mypwd