Transcript 대전IT개발자컨퍼런스
iBATIS 2
이동국
NHN
September 28th, 2008
Overview
•
•
•
•
소개
사용하기
iBATIS 3.0 소식
현재 진행중인 이슈
소개
iBATIS..?
Simple
Lightweight
소개
소개
매우 간단한 XML서술자를 사용해서 클래스와 SQL구문을 매핑하는
퍼시스턴스 프레임워크
CLASS
4
XML
SQL
소개
JDBC와 iBATIS
JDBC
conn = DriverManager.getConnection(url, user, pass);
stmt = conn.prepareStatement();
String sql = "SELECT * FROM employees";
rs = stmt.executeQuery(sql);
while (rs.next()) {
rs.getString("...");
rs.getString("...");
...
}
rs.close();
stmt.close();
conn.close();
5
소개
JDBC와 iBATIS
iBATIS
sqlMapClient.queryForList("selectEmployees")
<select id="selectEmployees" resultClass="Employee">
SELECT * FROM employees
</select>
6
소개
JDBC와 iBATIS
JDBC
conn = DriverManager.getConnection(url, user, pass);
String sql = "insert into employees values(?,?,?,?)";
stmt = conn.prepareStatement(sql);
stmt.setString(1, "..");
stmt.setString(2, "..");
stmt.setString(3, "..");
stmt.setString(4, "..");
int result = stmt.executeUpdate();
stmt.close();
conn.close();
7
소개
JDBC와 iBATIS
iBATIS
sqlMapClient.insert("insertEmployees", employee)
<insert id="insertEmployees" parameterClass="Employee">
insert into employees values(#id#,#name#,#val1#,#val2#)
</insert>
8
소개
JDBC와 iBATIS
3.0에서 추가될 코드 컨벤션에 따른 SQL구문 자동생성
Employee getEmployee(int id);
→ SELECT id, firstName, lastName FROM Employee WHERE id = #id#
List<Employee> listAllEmployees();
→ SELECT id, firstName, lastName FROM Employee
9
소개
장점과 단점
장점
SQL문과 소스 코드 분리로 소스 코드의 간결함을 유지 할 수 있다.
데이터베이스 자원에 대한 필요이상의 제어를 자동으로 해결해 준다.
단점
SQL문과 소스 코드를 분리한다는 점에서는 잇점이지만 오히려 지나치게 많은
파일을 생성해서 관리상의 어려움을 초래 할 수도 있다.
클래스 파일에 대한 리로드 기능은 WAS 및 기타 제품에 의해 적절히 보장 받을 수
있으나 XML 리로드에 대해서는 별도의 대책이 요구된다.
10
사용하기
데이터 타입
장점
11
단점
Bean
성능
컴파일시 타입및 이름검사
리팩토리
코드량 증가
Map
코드량 감소
느림
오류가 컴파일 시 체크되지 않고 실행 시
체크됨
잦은 형변환
사용하기
#과 $
#
SELECT * FROM account WHERE acc_id = #id#
→ SELECT * FROM account WHERE acc_id = ?
$
SELECT * FROM account WHERE acc_id = $id$
→ SELECT * FROM account WHERE acc_id = 1
12
사용하기
SQL 재사용하기
<sql id="selectAccount_frag">
SELECT
acc_id,
acc_first_name,
acc_last_name,
acc_email
FROM account
</sql>
<select id="selectAllAccounts" resultClass="Account">
<include refid="selectAccount_frag" />
</select>
13
사용하기
Result Map
일반적인 Result Map
<resultMap id="accountMap" class="Account">
<result property="id" column="acc_id" />
<result property="emailAddress" column="acc_email" />
</resultMap>
14
사용하기
Result Map
복합 Collection Result Map에 사용되는 객체 구조
public class Account {
private int id;
private String firstName;
.....
private List<AccountFamily> families = null;
-account
15
사용하기
Result Map
복합 Collection Result Map을 JDBC로 구현한다면
String accountSql = "SELECT * FROM account WHERE acc_id = ?";
String familySql = "SELECT * FROM Account_family WHERE acc_id = ?";
accountStmt = conn.prepareStatement(accountSql);
accountRs = accountStmt.executeQuery();
while (accountRs.next()){
accountRs.getString("...");
accountRs.getString("...");
familyStmt = conn.prepareStatement(familySql);
familyRs = familyStmt.executeQuery();
while( familyRs ){
familyRs.getString("");
...
}
account.setFamilies(...);
...
ResultSet내에서 하위
}
ResultSet 처리
16
사용하기
Result Map
복합 Collection Result Map
<resultMap id="get_account_nplus1" class="Account">
<result property="id" column="acc_id" />
<result property="families“
column="{id1=acc_id, id2=acc_id}"
select="SubList.selectFamilyList" />
</resultMap>
로그
Connection
Executing Statement: SELECT * FROM account WHERE acc_id = ?
Executing Statement: SELECT * FROM Account_family WHERE acc_id = ?
ResultSet
Header: [id, fullName]
Result: [1, HongGilDong] Result: [1, SpiderMan]
Header: [acc_id, acc_first_name, acc_last_name, acc_email, acc_id]
Result: [1, DongGuk, Lee, [email protected], 1]
17
사용하기
Result Map
복합 Collection Result Map에서 테이블조인을 JDBC로 구현한다면
String sql = "SELECT * FROM account a LEFT JOIN account_family f ON
a.acc_id = f.acc_id WHEREa.acc_id=?";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
int i = 0;
while (rs.next()){
family = new Family();
if( i == 0 ){
account.setId();
...
}
family.setId();
list.add(family);
i++;
}
18
사용하기
Result Map
복합 Collection Result Map
<resultMap id="get_account_family_avoidnplus1" class="Account"
groupBy="id">
<result property="id" column="acc_id" />
<result property="families"
resultMap="Base.get_family_avoidnplus1" />
</resultMap>
로그
Connection
Executing Statement: SELECT * FROM account a LEFT JOIN
account_family f ON a.acc_id = f.acc_id WHEREa.acc_id=?
ResultSet
Header: [acc_id, acc_first_name, acc_last_name, acc_email, acc_id,
family_fullname]
Result: [1, DongGuk, Lee, [email protected], 1, HongGilDong]
Result: [1, DongGuk, Lee, [email protected], 1, SpiderMan]
Result: [1, DongGuk, Lee, [email protected], 1, BatMan]
19
사용하기
파라미터 처리
인라인 파라미터
문법
#propertyName#
#propertyName:jdbcType#
#propertyName:jdbcType:nullValue#
샘플
<insert id="insertAccount">
INSERT INTO account (
acc_id, acc_first_name, acc_last_name, acc_email
) VALUES (
#id,jdbcType = INTEGER, javaType = int,
nullValue =-99999#, #firstName,
jdbcType = VARCHAR, javaType = string,nullValue=NULL#,
#lastName, jdbcType = VARCHAR, javaType = string,
nullValue = Hong#, #emailAddress, jdbcType = VARCHAR,
javaType = string, nullValue = NULL#
)
</insert>
20
사용하기
파라미터 처리
파라미터 맵
문법
<parameterMap id=”parameterMapName”
[class=”com.domain.Product”]>
<parameter property =”propertyName”
[jdbcType=”VARCHAR”]
[javaType=”string”]
[nullValue=“-9999”]
[typeName=”{REF or user-defined type}”]
[resultMap=someResultMap]
[mode=IN|OUT|INOUT]
[typeHandler=someTypeHandler]
[numericScale=2]/>
<parameter …… />
<parameter …… />
</parameterMap>
21
사용하기
파라미터 처리
샘플
<parameterMap id="accountParam" class="Account">
<parameter property="id" jdbcType="INTEGER" javaType="int“
nullValue="-9999999" />
<parameter property="lastName" jdbcType="VARCHAR"
javaType="string" nullValue="Hong" />
<parameter property="firstName" jdbcType="VARCHAR"
javaType="string" nullValue="NULL" />
<parameter property="emailAddress" jdbcType="VARCHAR"
javaType="string" nullValue="NULL" />
</parameterMap>
<insert id="insertAccount" parameterMap="Base.accountParam">
INSERT INTO account (acc_id, acc_first_name, acc_last_name,
acc_email
) VALUES ( ?,?,?,? )
</insert>
22
사용하기
파라미터 처리
대개는 인라인 파라미터에서 프로퍼티명만 표기하는 형태로 사용
파라미터맵을 명시하는 경우 파라미터 인덱스 값으로 값을 셋팅하기
때문에 쿼리문의 파라미터를 #프로퍼티명# 형태로 처리하지 않고 ?
형태로 처리해야 함
23
사용하기
동적 SQL
<dynamic>
이항연산 요소
<isEqual>
<isNotEqual>
<isGreaterThan>
<isGreaterEqual>
<isLessThan>
<isLessEqual>
24
사용하기
동적 SQL
단항연산 요소
<isPropertyAvailable>
<isNotPropertyAvailable>
<isNull>
<isNotNull>
<isEmpty>
<isNotEmpty>
파라미터 요소
<isParameterPresent>
<isNotParameterPresent>
<iterate>
25
사용하기
동적 SQL
단항연산 요소
<isPropertyAvailable>
<isNotPropertyAvailable>
<isNull>
<isNotNull>
<isEmpty>
<isNotEmpty>
파라미터 요소
<isParameterPresent>
<isNotParameterPresent>
<iterate>
26
사용하기
동적 SQL
<select id="getAccountByDynamicSQL" parameterClass="int" resultClass="Account">
SELECT acc_id, acc_first_name, acc_last_name, acc_email
FROM account
WHERE acc_id = #id#
<isNotEqual compareValue="1">
and acc_email = ''
</isNotEqual>
</select>
27
사용하기
동적 SQL
3.0 에서 추가될 동적 SQL
public class GetAccountListSQL extends SQLSource {
public String getSQL(Object param) {
Account acct = (Account) param;
append("select * from ACCOUNT");
prepend("WHERE");
if (exists(acct.getEmailAddress())) {
append("AND", "ACC_EMAIL like #EmailAddress#");
}
if (greaterThan(0, acct.getID())) {
append("AND", "ACC_ID = #ID#");
}
}
}
<Select id="getAccountList“
source="org.apache.GetAccountListSQL" ...>
28
사용하기
트랜잭션
자동 트랜잭션
메서드 호출 단위의 트랜잭션
로컬 트랜잭션
startTransaction
트랜잭션 시작
commitTransaction
트랜잭션 커밋
endTransaction
커밋이 되지 않은 경우 롤백, JDBC자원 회수
Spring과 같은 서비스 계층에서의 트랜잭션 관리
29
사용하기
캐시 타입
GC기반
MEMORY
시간 기반
LRU
FIFO
외부 캐시
OSCACHE
30
사용하기
캐시
캐시되는 데이터
SQL맵 구문 아이디
실제 쿼리문
com.ibatis.sqlmap.engine.mapping.statement 아래 각각의 Statement 객체 내 메서드 명
예) executeQueryForList
이외 iBATIS의 캐시 객체에서 지정하는 몇 가지 값들
31
사용하기
Spring에서 iBATIS 사용하기
SqlMapClientDaoSupport 를 통해 SqlMapClientTemplate
사용하기
mappingLocations
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation“
value="classpath:kr/or/openframework/dao/ibatis/SqlMapConfig.xml"/>
<property name="mappingLocations"
value="classpath:kr/or/openframework/dao/ibatis/AccountWithFamily*.xml“
/>
</bean>
Spring 2.5.5 에서 추가됨
iBATIS 2.3.2 이상의 버전이 필요함
32
사용하기
Spring에서 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>
<settings
cacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="false"
useStatementNamespaces="true" />
<sqlMap resource="openframework/dao/ibatis/Dummy.xml" />
<!--sqlMap resource="openframework/dao/ibatis/Account1.xml" />
<sqlMap resource="openframework/dao/ibatis/Account2.xml" />
<sqlMap resource="openframework/dao/ibatis/Account3.xml" />
<sqlMap resource="openframework/dao/ibatis/Account4.xml" /-->
</sqlMapConfig>
33
사용하기
성능을 향상시키는 방법
parameterMap 이나 parameterClass 속성을 명시적으로 선언
<update id="updateAccount" parameterClass="Account">
</update>
<resultMap> 를 명시적으로 정의하고 결과의 재매핑
(remapResults = true)옵션은 사용하지 말라.
Map이나 XML이 아닌 자바 Bean을 사용하라.
표현이나 배열 또는 혼합된 Bean이나 Map 프로퍼티가 아닌 간단한
프로터티를 사용하라.
<settings> 요소에 바이트코드 향상 기능을 활성화한다.
- enhancementEnabled="true"
34
iBATIS 3.0 소식
iBATIS 3.0 소식
SQL구문을 설정하는 애노테이션 추가
@Select("SELECT #id(EMP_ID:NUMERIC), #name(NAME:VARCHAR) ",
"FROM EMPLOYEE")
List<Employee> selectAllEmployees();
@Select({"SELECT #id(EMP_ID:NUMERIC), #name(NAME:VARCHAR) ",
"FROM EMPLOYEE ",
"WHERE EMP_ID = @id"})
Employee selectEmployee(int id);
35
iBATIS 3.0 소식
iBATIS 3.0 소식
ResultMap을 대체하는 애노테이션
@ResultClass (Employee.class)
@PropertyResults({
@Result(property="departments.id", column="D.DEPT_ID"),
@Result(property="departments.name", column="D.NAME"),
})
@Collections ({
@Collection(type=Department.class, property="departments",
groupBy="id"),
})
@Select("SELECT #id, #name, " +
"#departments.id, #departments.name " +
"FROM COMPANY C, DEPARTMENT D " +
"WHERE C.COMP_ID = D.COMP_ID")
List<Company> selectAllCompaniesWithJoin();
36
현재 진행중인 이슈
현재 진행중인 이슈
Support for JDBC 3 Named parameters
http://issues.apache.org/jira/browse/IBATIS-96
이를테면 다음과 같은 형태의 parameterMap을 사용..
<parameterMap id="insert-product-param" class="com.domain.Product">
<parameter property="description" parameter="desc" />
<parameter property="id" parameter="productId" />
</parameterMap>
37
현재 진행중인 이슈
현재 진행중인 이슈
Auto Reloading Sql-map configuration.
By Observing modifed date (adding datetime in Variables)
or making a method reload conf.
http://issues.apache.org/jira/browse/IBATIS-208
sqlmap 설정파일에 대한 Hot Deploy 기능 지원
38
현재 진행중인 이슈
현재 진행중인 이슈
Improving startup time (Dynamically loading SQL maps
based on namespace)
http://issues.apache.org/jira/browse/IBATIS-425
설정파일이 너무 많은 경우 WAS가 정상적으로 시작되는 시간이 너무 오래 걸려서
운영 시 어려움이 있다.
namespace기반으로 초기 일부만 로딩하고 나머지는 해당 namespace를 기준으로
차후 로딩을 하는 형태의 기능 요청.
39
현재 진행중인 이슈
현재 진행중인 이슈
Ability to build SqlMapClient programmatically without
SqlMapConfig.xml file
http://issues.apache.org/jira/browse/IBATIS-416
Spring과 사용하는 경우 sql-map-config.xml 파일에는 특별히 많은 내용이
들어가지 않기 때문에 별도로 설정파일을 만들 필요 없이 iBATIS관련 API호출로
설정파일의 갯수를 줄이는 방안에 대한 요청.
이미 Spring에서도 버전을 올라가면서 관련 설정을 줄일 수 있는 기능을 하나씩
추가하고 있음.
40
현재 진행중인 이슈
현재 진행중인 이슈
Using Java constants in statements
http://issues.apache.org/jira/browse/IBATIS-147
parameterClass가 아닌 다른 상수만을 가지는 외부 클래스의 값을 SQL구문에서
그대로 사용하기 위한 기능 요청.
Support generics
http://issues.apache.org/jira/browse/IBATIS-273
JDK 1.5 이상에서 지원하는 제네릭을 지원해달라는 요청.
41
현재 진행중인 이슈
참고자료
관련 사이트
iBATIS - http://ibatis.apache.org
openframework 위키 –
http://openframework.or.kr/Wiki.jsp?page=PersistentLayer#refpersisten
tLayer-2
관련 서적
iBATIS 인 액션 (이동국, 위키북스)
Pro Spring (Rob Harrop, Jan Machac다)
42
감사합니다.