들어가기 전
JDBC 단점
- conn, stmt, pstmt, rs 변수 선언하고
- try-catch 메서드마다 계속나오고
- 쿼리 날리고
- finally로 자원반납해줘야하고
- 반복되는 쿼리도 너무 많아ㅏㅏ~~ 코드너무길어~~
프레임워크 장점
iBATIS
- 데이터베이스에 있는 자원들을 보다 편리하게 가져오기 위한 프레임워크
- JDBC의 반복적인 작업을 iBATIS가 해줌
- SQL 매퍼 + DAO 프레임워크
- 프레임워크를 사용하기위해서는 xml이나 properties파일로 환경설정을 미리 해줘야함
특징
- 코드와 SQL 분리를 통한 생산성 향상
- JDBC와 SQL를 유지하면서도 훨씬 더 적은 코드로 JDBC처럼 작동
- 유지보수시 Java코드 말고 다른거 고쳐도됨
- 추상화된 접근방법
- JDBC 프로그래밍에 필수적인 자원의 연결/해제 및 공통 에러처리 등을 통합 지원함으로써 쿼리의 실행에만 집중할 수 있는 추상화 제공
관련 소스 파일
SqlMapConfig.properties
- DB와 연결하는 정보를 properties 파일에 설정
SqlMapConfig.xml
< sqlMapConfig > 내부
< properties >
<properties resource="SqlMapConfig.properties" />
- DB 연결 정보가 담긴 properties파일의 내용을 읽어와 설정한다.
< settings >
<settings cacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="true"
maxRequests="32"
maxSessions="10"
maxTransactions="5"
useStatementNamespaces="true" />
- ibatis를 처리하기 위한 환경설정 부분
- useStatementNamespaces="true": VO담는 xml에 별칭 부여하겠다
< typeAlias >
<typeAlias alias="memVO" type="kr.or.ddit.member.vo.MemberVO"/>
- typeAlias: 타입에 대한 별칭
- 클래스 이름이 패키지명까지 기술할 때, 이것을 간단히 표시하기 위해서 alias를 지정
- 형식:
<typeAlias alias="alias명" type="클래스의 풀네임"/>
< transactionManager type="JDBC" >
- DB와의 연결을 처리하는 부분
- SqlMapConfig.properties에 설정해 놓은 정보를 이용하여 구성
- SIMPLE => SimpleDataSourceFactory
- 데이터소스를 제공하는 컨테이너가 없는 경우 connection을 제공하기 위해 기본적으로 pooling 데이터소스 구현을 제공
- iBATIS SimpleDataSource connection pooling을 기반으로 한다.
- DBCP => DbcpDataSourceFactory
- DataSource API를 통해 connection pooling 서비스를 제공하기 위해 DBCP를 사용한다.
- 이 DataSource는 어플리케이션/웹 컨테이너가 DataSource 구현물을 제공하지 못하거나 standalone 어플리케이션을 구동할 때 이상적
- JNDI => JndiDataSourceFactory
- 어플리케이션 컨테이너 내 JNDI 컨텍스트로부터 DataSource 구현물을 가져와야 한다.
- 이것은 어플리케이션 서버를 사용중이고 컨테이너 관리 connection pool과 DataSource가 제공될 때 사용한다.
- JDBC DataSource 구현물에 접근하기 위한 표준적인 방법은 JNDI 컨텍스트를 통하여 접근하는 것
<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 >
<sqlMap resource="kr/or/ddit/sqlmap/member.xml"/>
- 실제 처리할 SQL문의 xml문서를 따로 만든 후 이 태그로 연결하여 사용한다.
- 형식:
<sqlMap resource="경로명/파일명.xml"/>
member.xml
SQL 기본 태그
- select, insert, update, delete
- select
- 성공시 객체반환 (queryForList, queryForObject)
- 동적쿼리: <isNotEmpty> 사용 (아래 예시 참고)
- insert: 성공시 null 반환
- update, delete: 성공시 행의 갯수 반환
SQL 기본 태그의 속성
- id
- 해당 태그를 호출할 때 <sqlMap>태그의 namespace와 연결하여 사용하는 이름
- parameterClass
- sql문에 사용될 데이터가 들어있는 객체를 지정
- 보통 VO클래스, 자바의 자료형 이름등이 사용됨
- typeAlias로 지정한 alias명을 사용할 수 있음
- 생략 가능
- resultClass
- select 문을 실행한 결과를 담을 객체
- 보통 VO클래스, 자바의 자료형 이름
- resultMap으로 대체 가능
- 생략 불가
<sqlMap> 내부
- namespace를 "member"로 설정
- ##: 스트링이면 '', int면 ''없이 그냥 대입
- $$: 내가 넣는 데이터 그대로 삽입
<resultMap>
<resultMap class="memVO" id="memberMap">
<result property="memId" column="mem_id"/>
<result property="memName" column="mem_name"/>
<result property="memTel" column="mem_tel"/>
<result property="memAddr" column="mem_addr"/>
</resultMap>
- VO클래스의 변수명과 DB 테이블의 컬럼명을 매핑
- 이렇게 하지 않으면 iBatis가 데이터를 읽어온 것과 꺼내는거랑 매칭이 안되서 null 파티
<select>
<select id="getMemberAll" resultMap="memberMap">
SELECT * FROM MYMEMBER
</select>
<select id="getMember" resultMap="memberMap">
SELECT * FROM MYMEMBER WHERE MEM_ID = #memId#
</select>
<select id="getSearchMember" parameterClass="memVO" resultMap="memberMap">
SELECT * FROM MYMEMBER
WHERE 1=1
<isNotEmpty property="memId">
AND MEM_ID = #memId#
</isNotEmpty>
<isNotEmpty property="memName">
AND MEM_NAME = #memName#
</isNotEmpty>
<isNotEmpty property="memTel">
AND MEM_TEL = #memTel#
</isNotEmpty>
<isNotEmpty property="memAddr">
AND MEM_ADDR LIKE '%' || #memAddr# || '%'
</isNotEmpty>
</select>
- <isNotEmpty>★
- null, 0이 아닐 때 해당 태그의 쿼리문을 실행
<insert>
<insert id="insertMember" parameterClass="kr.or.ddit.member.vo.MemberVO">
INSERT INTO MYMEMBER
(MEM_ID, MEM_NAME, MEM_TEL, MEM_ADDR)
VALUES (#memId#, #memName#, #memTel#, #memAddr#)
</insert>
<update>
<update id="updateMember">
UPDATE MYMEMBER
SET MEM_NAME = #memName#
, MEM_TEL = #memTel#
, MEM_ADDR = #memAddr#
WHERE MEM_ID = #memId#
</update>
- 파라미터로 MemberVO 객체가 왔지만 태그 속성의 parameterClass는 생략가능하기때문에 적어주지 않았음
<delete>
<delete id="deleteMember" parameterClass="String">
DELETE FROM MYMEMBER WHERE MEM_ID = #memId#
</delete>
SqlMapClientFactory.java
- 여러 dao에서 같이 쓸 수 있도록 싱글톤으로
- MemberDaoImpl 생성자에 smc 객체 생성
public class SqlMapClientFactory {
private static SqlMapClient smc;
private SqlMapClientFactory() {}
public static SqlMapClient getInstance() {
if(smc == null) {
try {
Charset charset = Charset.forName("UTF-8");
Resources.setCharset(charset);
Reader rd;
rd = Resources.getResourceAsReader("SqlMapConfig.xml");
smc = SqlMapClientBuilder.buildSqlMapClient(rd);
rd.close();
} catch (IOException e) {
System.err.println("SqlMapClient 객체 생성 실패!!!");
e.printStackTrace();
}
}
return smc;
}
}
iBATIS 설명 출처