2.3 iBatis SqlMaps
- 자바오브젝트와 SQL 문 사이의 자동매핑 기능을 지원하는 ORM 프레임워크
- iBatis는 코드 내에서 자바오브젝트만을 이용해 데이터 로직을 작성할 수 있게 해주고 SQL을 별도의 파일로 분리해서 관리해주며, 오브젝트-SQL 사이의 파라미터 매핑 작업을 자동으로 해주기 때문에 많은 인기를 얻고 있는 기술
- 본격적인 ORM인 JPA나 하이버네이트처럼 새로운 DB 프로그래밍 패러다임을 익힐 부담X
- SQL을 그대로 이용할 수 있으면서도 JDBC 코드 작성의 불편함을 제거해주고, 도메인 오브젝트나 DTO를 중심으로 개발이 가능하다는 장점
- XML파일로 작성하므로 컴파일이 필요 없고, SQL 작성과 관리 또는 검토를 DBA와 같은 개발자가 아닌 사람에 맡길 수 있다는 장점
- SQL 매핑은 스프링 JDBC에도 지원하지만, iBatis는 매핑 이상의 많은 기능을 제공
2.3.1 SqlMapClient 생성
- 핵심 API는 SqlMapClient 인터페이스에 담겨 있음
- JDBC가 Connection, Statement, ResultSet을 생성해 사용하듯 iBatis를 이용하려면 SqlMapClient를 구현한 오브젝트가 필요
- 스프링에서는 SqlMapClient를 빈으로 등록해두고 DAO에서 DI 받아 사용해야 하기 때문에 SqlMapClient를 빈으로 등록해주는 팩토리 빈의 도움이 필요
- 스프링이 제공하는 SqlMapClient용 팩토리 빈은 SqlMapClientFactoryBean
iBatis 설정파일과 매핑파일
- iBatis를 이용하려면 공통 설정을 담은 XML 파일과 매핑정보를 담은 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">
<!-- 매핑정보를 담은 파일의 클래스 패스를지정, 매핑파일마다 <sqlMap> 태그를 추가 -->
<sqlMapConfig>
<sqlMap resource="springboot/learningtest/spring/ibatis/Member.xml"/>
</sqlMapConfg>
- DB 커넥션과 트랜잭션 관리를 위한 정보는 iBatis 설정파일이 아닌 스프링 빈으로 등록한 것을 사용하는게 바람직한 방법
- 스프링의 DI 기법으로 DataSource 변경도 쉽고 트랜잭션 기능을 iBatis DAO도 이용 가능
매핑파일
- SQL-오브젝트 사이의 매핑정보는 XML 파일로 만듬
- 사용할 SQL 문과 SQL 파라미터, 실행 결과를 자바 오브젝트로 변환할지에 대해 정의
- 각 SQL은 고유한 아이디를 가지며, DAO에서는 아이디를 이용해 SQL을 실행
- ‘#’으로 둘러싸인 부분은 이름 치환자 (스프링 JDBC의 ‘:’ 이용한 것과 비슷)
- 테이블의 컬럼 이름과 매핑할 오브젝트의 프로퍼티 이름이 일치하면 자동으로 파라미터와 결과의 전환이 가능, 불일치할 경우 매핑 정보를 추가
<?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 namespace="Member">
<typeAlias alias="Member" type="springbook.learningtest.spring.jdbc.Member"/>
<delete id="deleteMemberAll">
delete from member
</delete>
<insert id="insertMember" parameterClass="Member">
insert into member(id, name, point) values(#id#, #name#, #point#)
</insert>
<select id="findMemberById" parameterClass="int" resultClass="Member">
select * from member where id = #id#
</select>
<select id="findMembers" resultClass="Member">
select * from meber order by id
</select>
</sqlMap>
SqlMapClient를 위한 SqlMapClientFactoryBean 등록
- DAO가 iBatis 기능을 사용하려면 SqlMapClient가 필요
- JDBC의 Connection처럼 모든 데이터 액세스 작업에 필요로 하는 오브젝트
- SqlMapClient를 싱글톤 빈으로 등록해서 필요한 DAO에서 DI받아 사용 가능
- 멀티 스레드에서 공유해서 사용해도 안전한 오브젝트
- SqlMapClientFactoryBean을 이용해 팩토리 빈이 생성해줘야 함, 필요한 프로퍼티는 DataSource와 앞에서 만들어둔 설정파일의 위치
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapCleintFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation"
value="springbook/learningtest/spring/ibatis/SqlMapConfig.xml" />
</bean>
2.3.2 SqlMapClientTemplate
- iBatis용 DAO는
SqlMapClient
빈을 DI 받아서 iBatis 기능을 이용
SqlMapClient
를 직접 사용하는 대신 스프링이 제공하는 템플릿 오브젝트인SqlMapClientTemplate
를 이용하는 것이 좋음- 스프링 데이터 액세스 기술이 제공하는 다양한 혜택을 제공 받음
- 사용방법은 JdbcTemplate과 거의 유사하며, 예외 변환, 스프링 트랜잭션과 동기화 등이 지원
public class MemberDao {
private SqlMapClientTemplate sqlMapClientTemplate;
public void setSqlMapClient(SqlMapClient sqlMapClient) {
sqlMapClientTemplate = new SqlMapClientTemplate(sqlMapClient);
}
- SqlMapClientTemplate를 직접 생성하는 대신 스프링이 재공하는 SqlMapClientDaoSupport를 상속해 DAO를 만들어도 사용 가능
- SqlMapClient를 DI 받아서 템플릿을 만들어주는 기능이 포함
- 템플릿 오브젝트는 getSqlMapClientTemplate()로 가져와서 사용 가능
public class MemberDao extends SqlMapClientDaoSupport { public void insert(Member member) { getSqlMapclientTemplate().insert("insertMember", member); } }
등록, 수정, 삭제
insert()
- SQL 아이디와 파라미터 오브젝트를 넣어주면 해당 INSERT 문을 실행
- 내부적으로 iBatis의 SqlMapExecutork의 isnert()가 사용
Ojbect insert(String statementName)
Object insert(String statementName, Object parameterObject)
update()
- SQL 아이디와 파라미터 오브젝트를 제공하면 해당 UPDATE 문을 실행
- 내부적으로 SqlMapExecutor의 update()가 사용
int update(String statementtName)
int update(String statementName, Object parameterObject)
//영향을 받은 로우의 개수를 체크
//기대했던 로우의 개수와 실행결과가 일치하지 않으면 예외가 발생
void update(String statementName, Object parameterObject,
int requiredRowsAffected)
delete()
- 매핑파일에 정의된 DELETE문을 실행
- SqlMapExecutor의 delete() 가 사용
- 메소드의 실행은 update()와 비슷
int delete(String statementName)
int delete(String statementName, Object parameterObject)
void delete(String statementName, Object parameterObject,
int requiredRowsAffected)
- sqlMapClientTemplate을 갖고 있는 DAO라면 아래와 같이 작성 가능
public void insert(Member member) { sqlMapClientTemplate.insert("insertMember", member); } public void deleteAll() { sqlMapClientTemplate.delete("deleteMemberAll"); }
조회
단일 로우 조회: queryForObject()
- SQL의 실행 결과가 한 건인 경우에 사용
- 리턴 오브젝트는 매핑파일에 지정된 타입이 사용
Object queryForObject(String statementName)
Object queryForObject(String statementName, Object parameterObject)
Object queryForObject(String statementName, Object parameterObject,
Object resultObject)
다중 로우 조회: queryForList()
- SQL 실행 결과가 한 건 이상인 경우 각 로우를 오브젝트에 담고 리스트로 리턴
List queryForList(String statementName)
List queryForList(String statementName, Object ParameterObject)
List queryForList(String statementName, int skipResult, int maxResults)
List queryForList(String statementName, Object parameterObject, int skipResults,
int maxResults)
다중 로우 조회: queryForMap()
- 스프링 JDBC의 queryForMap()과 이름은 비슷하지만 맵에 내용이 담기는 방식은 전혀 다르므로 주의가 필요
- iBatis의 queryForMap()은 다중 로우를 가진 결과를 조회할 때 사용
- 맵의 키는 지정된 컬럼 값이 사용
Map queryForMap(String statementName, Object parameterObject,
String keyProperty)
Map queryForMap(String statementName, Object parameterObject,
String keyProperty, String valueProperty)
다중 로우 조회: queryWithRowHandler()
- 스프링 JDBC의
RowMapper
처럼 SQL의 결과를 루프로 돌면서 각 로우마다 콜백 오브젝트를 호출해주는 방식
RowMapper
는 각 로우를 매핑해서 돌려주는 것이 목적인 데 반해서queryWithRowHandler()
의RowHandler
는 그 자체로 해당 로우를 매핑한 결과를 어떻게 처리할지를 스스로 결졍
- 조회된 로우의 개수가 매우 많다면 리스트나 맵에 담는 것보다 각 로우를 직접 처리하는 방법을 쓰는편이 좋음
RowHandler
는 iBatis에서 직접 제공되는 콜백 인터페이스
queryWithRowHandler()
는 결과를 리스트에 담는 목적이 아니라 리턴이 없음
void queryWithRowHandler(String statementName, RowHandler rowHandler)
void queryWithRowHandler(String statementName, Object parameterObject,
RowHandler rowHandler)
SqlMapClientCallback
- 콜백이 내장된 템플릿 메소드를 이용하는 대신 직접 iBatis의 SqlMapExecutor의 API를 사용하고 싶다면 SqlMapClientCallback 인터페이스를 사용
public interface SqlMapClientCallback<T> {
T doInSqlMapClient(SqlMapExecutor executor) throw SQLException;
}
- 이 인터페이스를 구현한 콜백 오브젝트를 SqlMapClientTemplate의 execute()에 전달
public <T> T execute(SqlMapClientCallback<T> action)
- SqlMapClientCallback은 iBatis API의 사용법을 충분히 숙지 후 스프링 템플릿/콜백 방식의 동작원리를 잘 이해한 후에 사용
'개발서적 > 토비 스프링 3.1-Vol.2' 카테고리의 다른 글
[토비의 스프링 - Vol.2] 2장 - 2.4 JPA (0) | 2022.01.17 |
---|---|
[토비의 스프링 - Vol.2] 2장 - 2.2 JDBC (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 2장 - 2.1 공통개념 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.5.5 프로퍼티 소스 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.5.4 런타임 환경 추상화와 프로파일 (0) | 2022.01.17 |