728x90

소개

요즈음 많은 일은 다른 프레임워크를 이끄는 것처럼 보이는 Hibernate를 이용한 객체-관계 맵핑 필드에서 이루어진다. 그러나 객체-관계 맵핑 툴을 사용할때 한가지 문제점이 있다. 대부분의 데이터베이스 관리자는 OR맵핑 툴에 의해서 생성된 쿼리문이 다소 편안해 보이지 않는다는 것이다.
슬프게도 데이터베이스 관리자는 당신의 프레임워크가 당신을 위해 자동적으로 생성해주는 쿼리문을 분명하게 이해하지를 못한다는 것이다. 그리고 이것이 어떻게 당신의 애플리케이션을 유연하게 만드는지 알지 못한다. 그들은 당신의 애플리케이션의 가장 중요한 병목현상을 가져오는 데이터베이스라는것을 느낀다. 당신은 SQL쿼리문을 넘어서 완벽한 제어를 해야만 한다. 그러면 그들은 분석이 가능하게 되고 성능을 제대로 관리할수 있게 된다.

그러나 문제는 당신이 OR맵핑툴을 사용하지 않을때 하위레벨의 JDBC코드를 쓰거나 관리할때 많은 자원을 소비한다는 것이다. 모든 JDBC애플리케이션은 다음과 같은 반복코드를 가진다.

  1. 데이터베이스 연결및 트랜잭션 관리
  2. 쿼리 파라미터를 자바객체와 셋팅하기.
  3. SQL ResultSets를 자바 객체로 변환하기.
  4. 쿼리문 생성하기.

iBatis SQLMaps 프레임워크는 당신이 일반적으로 관계형 데이터베이스에 연결이 필요한 많은 자바코드의 명백하게 감소시키는데 도움을 준다. 이것은 위의 걱정거리중 3가지 문제를 없애도록 해준다. PreparedStatement파라미터와 ResultSet값에 자바빈 객체의 쉬운 맵핑을 하도록 해준다. SQLMaps의 기본적인 철학은 간단함(simple)이다. JDBC의 기능의 80%를 제공하는 간단한 프레임워크를 제공한다.

이 글은 SQLMaps프레임워크를 사용하는 방법에 대한 단계적인 설명서이다. 우리는 샘플 Struts애플리케이션을 생성함으로써 시작하고 SQLMaps를 사용하기 위해서 설정할것이다. 그런 다음 우리는 SELECT, INSERT, UPDATE 등등 같은 기본적인 데이터베이스 작업을 수행하는 방법에 대해서 다둘것이다. 그리고 나서 우리는 데이터베이스 연결과 트랜잭션 관리를 위해 제공하는 SQLMaps의 옵션을 다둘것이다. 그리고 마지막으로 우리는 캐쉬와 페이징 같은 SQLMaps의 몇몇 향상된 기능을 사용하도록 할것이다.

SQLMaps의 기본적인 생각

SQLMaps프레임워크를 사용하기 위해 당신은 당신의 애플리케이션을 통해 실행될 SQL쿼리문의 모든 리스트를 가지는 XML파일을 생성한다. 각각의 SQL쿼리를 위해 당신은 쿼리문이 파라미터와 ResultSets을 교체되는 자바 클래스를 정의한다.

당신의 자바 코드내에서 당신이 특정 쿼리문을 실행하길 원할때 당신은 쿼리 파라미터와 필요한 조건을 넘기기 위한 객체를 생성할 것이고 SQLMaps를 실행하기 위한 쿼리의 객체와 이름을 넘겨준다. 쿼리가 실행되었을때 SQLMaps는 쿼리 결과를 받기 위해 정의된 클래스의 인스턴스를 생성할 것이고 데이터베이스에 의해 반환된 ResultSet로 부터 넘겨진 값으로 이것을 생성할것이다.

SQLMaps를 사용한 간단한 애플리케이션(Hello World)

우리는 SQLMaps를 사용하기 위한 당신의 애플리케이션내에서 변경이 필요한 샘플 Struts애플리케이션을 생성함으로써 시작할것이다. 이 샘플을 위한 코드는 밑의 Resource부분에서 찾을수 있다. 이 샘플에서 contactId를 위해 유저에게 요청하는 JSP페이지를 생성하는 애플리케이션이다. 이것이 submit되었을때 우리는 다른 JSP를 사용해서 유저에게 보여주기 주는 CONTACT테이블내의 contact를 찾기 위해 이것을 사용한다. 다음의 단계적인 지시사항을 따르도록 하라.

1. ibatis-sqlmap-2.jar 와 ibatis-common-2.jar 를 당신의 web-inf/lib 디렉토리에 복사하라.

2. 다음처럼 자바 소스 폴더에 SqlMapConfig.xml파일을 생성하라.

<sqlMapConfig>
    <settings useStatementNamespaces="false" />
    <transactionManager type="JDBC">
        <dataSource type="SIMPLE" >
            <property name="JDBC.Driver"
                value="COM.ibm.db2.jdbc.app.DB2Driver"/>
            <property name="JDBC.ConnectionURL"
                value="jdbc:db2:SAMPLE"/>
            <property name="JDBC.Username"
                value="db2admin"/>
            <property name="JDBC.Password"
                value="admin2db"/>
        </dataSource>
    </transactionManager>
    <sqlMap resource="Contact.xml"/>
</sqlMapConfig>

SqlMapConfig.xml은 SQLMaps를 위한 배치서술자(deployment descriptor)이고 다음의 구성요소(element)를 가진다.

  • <sqlMapConfig> 는 파일의 가장 상위 구성요소이다. <settings> 는 애플리케이션 레벨의 셋팅을 정의하기 위해서 사용되었다. 예를 들면 useStatementNamespaces 속성은 prepared statement의 모든 충분한 이름을 사용하기를 원하는지 원하지 않는지를 정의할때 사용된다. 이것은 캐쉬와 lazy초기화를 제어하기 위해 몇개의 더 많은 속성을 사용할수도 있다. 더 많은 속성에 대해서는 문서를 참조하라.
  • <transactionManager> 는 당신의 애플리케이션에서 사용되길 원하는 어떤 종류의 트랜잭션 관리를 정의하기 위해서 사용된다. 우리의 샘플 애플리케이션에서 우리는 트랜잭션을 관리하기 위해서 Connection객체의 commit와 rollback메소드를 사용하길 원한다. 그래서 우리는 트랜잭션 관리자 처럼 JDBC를 사용한다. 이것은 자식 구성요소처럼 당신이 사용하길 원하는 Connection관리 타입을 정의하는 <dataSource>을 포함한다. 우리의 샘플 애플리케이션에서 우리는 SQLMaps의 connection pooling의 구현을 사용하길 원한다. 그래서 SIMPLE타입의 데이터베이스를 사용한다. SQLMaps는 JDBC드라이버 이름, URL, connection pooling을 생성하기 위한 비밀번호같은 정보를 요구한다. 그래서 우리는 정보를 전달하기 위해 <property> 를 사용한다. 우리는 나중에 다양한 트랜잭션과 connection관리옵션을 다룰것이다.
  • <sqlMap> 는 sqlmap설정 파일들을 선언하기 위해 사용된다. 더 쉽게 논의된 파일들은 당신이 수행하길 원하는 SQL쿼리의 리스트이다.

3. firstName, lastname그리고 contactId의 속성과 관련된 getter그리고 settter메소드를 가지는 Contact.java라는 이름의 자바빈 클래스를 생성한다. 이 클래스는 쿼리 파라미터를 전달하고 ResultSet로 부터 값을 읽기 위해서 사용될것이다.

public class Contact implements Serializable{
	private String firstName;
	private String lastName;
	private int contactId;
	//Getter setter methods for firstName,
	//lastName and contactId property
}

4. 다음처럼 우리는 실행하길 원하는 모든 Contact테이블 관련 SQL쿼리문의 리스를 가지는 Contact.xml파일을 생성한다.

<sqlMap namespace="Contact"">
    <typeAlias alias="contact"
        type="com.sample.contact.Contact"/">
    <select id="getContact"
        parameterClass="int" resultClass="contact"">
            select CONTACTID as contactId,
                   FIRSTNAME as firstName,
                   LASTNAME as lastName from
                   ADMINISTRATOR.CONTACT where CONTACTID = #id#
    </select>
</sqlMap>

파일내에서 사용된 태그는 다음과 같다.

  • <sqlMap> 는 파일의 가장 상위 요소이다. 당신의 애플리케이션은 대개 하나 이상의 테이블을 가질것이고 당신은 다른 namespaces에 다른 테이블을 관계시키는 쿼리문을 분리시키길 원할것이다. <namespace> 요소는 위치되어야 할 파일 내에 모든 쿼리문의 namespace를 정의하는데 사용된다.
  • <typeAlias> 는 Contact클래스의 완전한 이름(경로를 포함한)을 위한 짧은 이름을 선언하기 위해 사용된다. 이 선언 뒤에 짧은 이름은 완전한 이름(경로를 포함한) 대신에 사용될수 있다.
  • <select> 는 SQLMaps프레임워크내에서 SELECT쿼리문을 선언하기 위해서 사용된다. 당신은 요소의 값처럼 실행하기 위한 쿼리문을 정의할수 있다. id속성은 이 특정 쿼리문을 실행하기 위해 SQLMaps에 지시하기 위하 사용되는 이름을 정의하기 위해서 사용된다. parameterClass 는 쿼리 파라미터를 전달하기 위해서 사용되는 클래스를 정의하는데 사용되고 resultClass는 ResultSet으로 부터 값을 반환하기 위해서 사용되는 클래스의 이름을 제공한다.

5. 우리의 Action클래스의 execute()메소드의 내부에서 우리는 SQLMaps와 상호작동하는 SqlMapClient의 인스턴스를 생성한다. 우리는 설정값을 읽는데 사용되는 SqlMapClientBuilder를 위해 SqlMapConfig.xml 파일을 전달한다.

    DynaActionForm contactForm =
        (DynaActionForm)form;
    Reader configReader =
        Resources.getResourceAsReader("SqlMapConfig.xml");
    SqlMapClient sqlMap =
        SqlMapClientBuilder.buildSqlMapClient(configReader);
    Contact contact = (Contact)
        sqlMap.queryForObject("getContact",
                    contactForm.get("contactId"));
    request.setAttribute("contactDetail", contact);
    return mapping.findForward("success");

SQLMaps의 queryForObject 메소드는 SELECT쿼리문을 실행하기를 원할때 사용된다. Contact.xml에서 우리는 parameterClass 클래스처럼 정의된 int값을 가지고 우리는 getContact같은 쿼리문의 이름으로 integer처럼 contactId를 전달한다. SQLMaps는 Contact클래스의 객체를 반환할것이다.

기본적인 데이터베이스 작업

지금부터 우리는 SQLMaps를 사용해서 몇개의 기본적인 데이터베이스 작업을 수행하는 방법에 촞점을 맞출것이다.

1. Insert

우리는 INSERT쿼리문을 수행하는 방법부터 시작할것이다.

<insert id="insertContact" parameterClass="contact">
INSERT INTO ADMINISTRATOR.CONTACT( CONTACTID,FIRSTNAME,LASTNAME)
        VALUES(#contactId#,#firstName#,#lastName#);
 </insert>

<insert> 는 INSERT SQL쿼리문을 선언하는데 사용된다. 이것은 요청 파라미터를 전달하는데 사용되는 자바빈 클래스를 표시하기 위해 parameterClass 속성을 가질것이다. 우리는 새로운 레코드를 추가하는 동안 contactId속성의 값을 사용하길 원한다. 그래서 우리는 우리의 SQL쿼리문에 #contactId#를 사용한다.

public void contactInsert() throws SQLException, IOException {
    sqlMap.startTransaction();
    try {
    sqlMap.startTransaction();
    Contact contact = new Contact();
    contact.setContactId(3);
    contact.setFirstName("John");
    contact.setLastName("Doe");
    sqlMap.insert("insertContact",contact);
    sqlMap.commitTransaction();
    } finally{
        sqlMap.endTransaction();
    }
}

우리의 자바코드내에서 우리는 Contact객체를 생성한다. 그것의 값을 보여주고 sqlMap.insert()를 호출한다. 그리고 실행하기 위한 쿼리의 이름을 Contact에 전달한다. 이 메소드는 새로운 contact를 추가할것이고 새롭게 추가된 contct의 기본키(primary key)를 반환할것이다.

기본적으로 SQLMaps는 하나의 작업같은 모든 DML메소드를 처리한다. 그러나 당신은 트랜잭션 경계구분을 위한 startTransaction, commitTransaction, 그리고 endTransaction을 사용할수 있다. 당신은 startTransaction()메소드를 호출함으로써 트랜잭션을 시작할수 있고
이것은 connection pool로 부터 connection를 가져온다. 이 connection객체는 이 트랜잭션 내에서 쿼리문을 실행하기 위해서 사용될것이다. 만약에 트랜잭션내의 모든 쿼리문이 성공적으로 실행되었다면 당신은 당신의 변경을 반영하기 위해서 commitTransaction()를 호출해야만 한다. 당신의 트랜잭션이 성공하느냐 마느냐에 상관없이 당신은 마지막에 pool에 connection객체를 반환하는 endTransaction메소드를 호출해야만 하고 이는 적합한 초기화를 수행한다.

2. Update

<update> 는 update쿼리문을 선언하는데 사용된다. 이것의 parameterClass 요소는 쿼리 파라미터를 전할하는데 사용되는 자바빈 클래스의 이름을 선언하는데 사용된다. 당신의 자바코드 내부에서 당신은 sqlMap.update("updateContact",contact)와 함께 update쿼리문을 실행하도록 SQLMaps에게 지시할수 있다. 이 메소드는 영향을 입은 row의 갯수를 반환할것이다.

<update id="updateContact" parameterClass="contact">
update ADMINISTRATOR.CONTACT SET
FIRSTNAME=#firstName# ,
LASTNAME=#lastName#
where contactid=#contactId#
</update>

3. Delete

<delete> 는 DELETE쿼리문을 선언하는데 사용된다. 당신의 자바 코드내에서 당신은 sqlMap.delete("deleteContact",new Integer(contactId))와 같은 statement를 실행한다. 이 메소드는 영향을 끼친 row의 갯수를 반환한다.

<delete id="deleteContact" parameterClass="int">
DELETE FROM ADMINISTRATOR.CONTACT WHERE CONTACTID=#contactId#
</delete>

4. Procedure

저장 프로시저는 theprocedureelement를 통해 지원이 된다. 대부분의 저장 프로시저는 IN, INOUT, 또는 OUT 타입의 몇개의 파라미터를 가진다. 그래서 당신은 <parameterMap> 요소를 생성하고 저장 프로시저에 전달하고자 하는 파라미터의 리스트를 생성한다. parameterMap객체는 만약에 파라미터 타입이 OUT또는 INOUT일때만 변경이 된다.

<parameterMap id="swapParameters" class="map" >
    <parameter property="contactId" jdbcType="INTEGER"
        javaType="java.lang.Integer" mode="IN"/>
    <parameter property="firstName" jdbcType="VARCHAR"
        javaType="java.lang.String" mode="IN"/>
    <parameter property="lastName" jdbcType="VARCHAR"
        javaType="java.lang.String" mode="IN"/>
</parameterMap>

<procedure id="swapContactName" parameterMap="swapParameters" >
{call swap_contact_name (?, ?,?)}
</procedure>

처음에 당신의 자바코드내에서 프로시저에 전달하고자 하는 파라미터의 HashMap를 생성하라. 그리고 실행되기 원하는 쿼리의 이름에 sqlMap를 전달해라.

HashMap paramMap = new HashMap();
paramMap.put("contactId", new Integer(1));
paramMap.put("firstName", "Sunil");
paramMap.put("lastName", "Patil");
sqlMap.queryForObject("swapCustomerName", paramMap);

Connection 그리고 트랜잭션 관리.

SQLMaps프레임워크는 당신을 위해 connection관리를 한다. 기본적으로 이것은 connection관리의 3가지 다른 구현을 가지고 있다. 당신은 <dataSource> 의 type속성의 값에 의해서 사용하길 워하는 구현을 정의할수 있다.

  1. SIMPLE : SQLMaps의 connection pool구현. 이 구현을 사용하는 동안 당신은 connection정보(JDBC드라이버이름, 유저이름, 비밀번호같은)를 SQLMaps에 전달해야만 한다.
  2. DBCP : 아파치의 DBCP connection pooling알고리즘을 사용한다.
  3. JNDI : 제공되는 데이터소스를 사용한다. 만약에 당신이 이 메소드를 사용하길 원한다면 먼저 당신의 컨테이너에 JDBC데이터소스를 설정해야 한다. 그리고 다음처럼 데이터소스의 JNDI의 이름을 정의하라.
<transactionManager type="JDBC" >
    <dataSource type="JNDI">
        <property name="DataSource"
            value="java:comp/env/jdbc/testDB"/>
    </dataSource>
</transactionManager>

데이터소스 속성의 값은 사용하길 원하는 데이터소스의 JNDI이름을 가리킨다. SQLMaps는 connection관리를 위해 DataSourceFactory 구현을 사용한다. 그래서 당신은 이 인터페이스의 당신 자신만의 클래스 구현을 생성할수 있고 이것을 사용하도록 SQLMaps에 알릴수 있다.

트랜잭션 관리를 위해 SqlMapConfig.xml안의 <transactionManager> 의 값은 트랜잭션 관리를 위해 사용되어야 하는 클래스를 가리킨다.

  1. JDBC : 이 경우에 트랜잭션은 Connection객체의 begin()과 commit()을 호출함으로써 제어된다. 이 옵션은 컨테이너 밖에서 수행되는 애플리케이션내에서 사용되어야 하고 하나의 데이터베이스와 상호작동해야한다.
  2. JTA : 이 경우에 전역적인 JTA트랜잭션이 사용된다. SQLMaps활동은 다른 데이터베이스와 트랜잭션 자원을 가능한 포함하는 넗은 범위(wider-scope)의 트랜잭션부분 처럼 속한다.
  3. External : 이 경우에 당신은 당신 자신의 트랜잭션을 관리해야만 한다. 트랜잭션은 프레임워크 생명주기의 부분처럼 commit나 rollback되지는 않을것이다. 이것은 읽기전용같은 비 트랜잭션 데이터베이스에 유용하다.

향상된 기능.

지금 우리는 SQLMaps프레임워크의 향상된 기능에 대해 얘기할 조금의 시간을 보낼수 있다. 이 글의 범위는 그 향상된 기능의 모든것을 볼 시간을 할애하지는 않았다. 그래서 내가 생각하는 공통적으로 유용한 몇개에 대해서만 얘기할것이다. 나머지는 SQLMaps문서를 통해 볼수 있다.

캐슁(Caching)

<cacheModel> 는 쿼리-맵핑 statement를 사용하기 위해 cache를 서술하기 위해 사용된다.

12345678901234567890123456789012345678901234567890
  <cacheModel id="contactCache" type="LRU">
  <flushOnExecute statement="insertContact"/>
  <flushOnExecute statement="updateContact"/>
  <flushOnExecute statement="deleteContact"/>
      <property name="size" value="1000"/>
  </cacheModel>

  <select id="getCachedContact" parameterClass="int"
    resultClass="contact" cacheModel="contactCache">
    select FIRSTNAME as firstName,LASTNAME as lastName
        from CONTACT where  CONTACTID = #contactId#
  </select>

각각의 쿼리는 다른 캐쉬 모델또는 같은 캐쉬를 공유할수 있는 단 하나의 쿼리보다 많은 여러개의 쿼리를 가질수 있다. SQLMaps는 제공되는 다른 타입의 캐쉬를 위해 플러그인이 가능한 프레임워크를 지원한다. 사용될수 있는 구현은 cacheModel 요소의 type속성에서 정의된다.

  1. LRU : 캐쉬가 full상태가 되었을때 캐쉬로 부터 최근에 사용된 요소를 제거한다.
  2. FIFO : 캐쉬가 full상태가 되었을때 캐쉬로 부터 가장 오래된 객체를 제거한다.
  3. MEMORY : 캐쉬를 관리하기 위해서 SOFT, WEAK, 그리고 STRONG 같은 자바 참조 타입을 사용한다. 이것은 메모리에 머물게 될 것을 결정하기 위해 garbage collector 를 허락한다. 사용될수 있는 구현은 메모리가 모자란 곳의 애플리케이션내에서 사용된다.
  4. OSCACHE : OSCache2.0 캐쉬 엔진을 위한 플러그인이다. 당신은 OSCache를 설정하기 위해서 가장 상위 폴더에 oscache.properties가 필요하다. 이 구현은 분산 애플리케이션에서 사용될수 있다.

<select> 의 cacheModel속성은 이것의 결과를 캐쉬하기 위해서 사용되는 캐쉬모델을 정의한다. 당신은 <settings> 의 cacheModelsEnabled 속성값을 false를 셋팅함으로써 SqlMapClient 를 위한 전역적인 캐슁을 불가능(disable)하게 할수 있다.

로깅을 가능하게 하는 방법.

SQLMaps는 Jakarta Commons logging프레임워크의 사용을 통해 로깅정보를 제공한다. 로깅을 가능하게 하기 위해서 다음의 단계를 따르라.

당신의 애플리케이션 클래스패스에 log4j.jar를 추가하라. 웹 애플리케이션을 위해 WEB-INF/lib에 복사해야할것이다. 당신의 클래스패스에 다음처럼 log4j.properties를 생성하라.

log4j.rootLogger=ERROR, stdout
# SqlMap logging configuration...
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

페이징(Paging)

CONTACT테이블이 1000레코드를 가지고 있고 유저를 위해 스페레드시트에서 이것을 표시할것을 원한다고 가정해보자. 하지만 한번에 50개의 레코드만 표시할수 있다. 이런 경우에 우리는 1000 contacts를 포함하는 ResultSet를 얻기위해 CONTACT테이블을 쿼리하길 원하지는 않는다. 우리는 CONTACT 테이블을 쿼리하길 원하고 한번에 50개의 레코드만 얻는다. SQLMaps는 이런 타입의 경우를 다루기 위해서 PaginatedList 인터페이스를 제공한다. 이것은 유저가 앞으로(forward) 그리고 뒤로(backward)를 탐색할수 있는 데이터의 부분집합을 당신에게 가지도록 허락한다.

PaginatedList list = sqlMap.queryForPaginatedList("getContacts", null, 2);
while (true) {
    Iterator listIterator = list.iterator();
    while (listIterator.hasNext()) {
        System.out.println(
            ((Contact)listIterator.next()).getContactId());
    }
    if( list.isNextPageAvailable())
        list.nextPage();
    else
        break;
}

결론

SQLMaps는 만약에 당신의 애플리케이션이 작은 수의 고정된 쿼리문을 가지고 있다고 할때 매우 좋은 옵션이다. 이것은 개발자가 이미 알고 있는 SQL에 대한 지식을 이용하기 때문에 매우 쉽다. 또한 각자의 역할을 구분하는 데 도움이 된다. 개발자는 필요한 쿼리문 목록을 작성하고 자바 코드에서 작업을 시작한다. SQLMaps XML파일을 받은 DBA는 SQL쿼리를 분석하고 튜닝한다.

장점

  1. OR맵핑 프레임워크에서 제공하는 Dialects 에 의존하지 않는다.
  2. 많은 향상된 기능을 제공하므로 사용하기 쉽다.
  3. EJBQL같은 새로운 쿼리언어를 배울 필요가 없다. 당신의 SQL문에 대한 기존 지식을 활용할 수 있다.

단점

  1. 만약에 향상된 기능을 사용한다면 어플리케이션은 이식가능하지 않다._(역자 주. 이는 SQLMaps의 고유의 특이한 기능을 사용하는 것이기 때문에 이식이 사실상 불가능함을 뜻하는것 같다.)_

하지만 애플리케이션이 다중 데이터베이스보다 더 복잡한 환경에서 작동하거나 많은 수의 쿼리문을 가진다면 마지막 결정을 하기 전에 다양한 OR맵핑 프레임워크를 살펴보는 것이 좋을 것이다._(역자 주. 비교적 간단한 데이터베이스 환경이나 적은 수의 쿼리문을 사용할 때 적합하다고 보는 것 같다. 하지만 여기서 비교적 간단한 데이터 베이스 환경이나 쿼리문의 적음이 뜻하는 바는 개발자마다 다르다고 생각한다. 개인적으로 적용해 본 후 판단하길 바라지만 국내의 대부분의 프로젝트가 이 제약을 넘어서지는 않을 것 같다는게 개인적인 생각이다.)_

Resources

Sample code for this article

iBatis home page

Struts home page

Sunil Patil has worked on J2EE technologies for four years. He is currently working with IBM Software Labs.


이 번역문은 네이버 카페에서 운영중인 Wiki에서 가져온 것입니다. 이 번역문의 원 URL은 http://openframework.or.kr/JSPWiki/Wiki.jsp?page=Hibernate입니다. 좋은 번역 해주신 이동국님에게 감사드립니다.

728x90

'JAVA' 카테고리의 다른 글

IBATIS 연산요소  (0) 2012.07.29
jstl 문자열 자르기  (0) 2012.07.29
class 파일 디컴파일러  (0) 2012.07.29
maven install 중 mojo : annotations are not supported  (0) 2012.07.29
Hudson 이란?  (0) 2012.07.29

+ Recent posts