대전IT개발자컨퍼런스

Download Report

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
감사합니다.