extends AbstractDAO

일반적으로 DAO(Data Access Object) 클래스에서는 Query 서비스를 활용하여 데이터 접근 로직을 처리한다. Anyframe Query 서비스에서는 이러한 DAO 클래스를 간편하게 개발할 수 있도록 하기 위해 anyfram.core.query.AbstractDAO 클래스를 제공하고 있으며 다음과 같은 특징을 지닌다.
  • 입력된 문자열에 정해진 Prefix, Postfix를 조합하여 query id를 만든다.

  • INSERT문의 경우 'createXXX', UPDATE문인 경우 'updateXXX', DELETE문인 경우 'removeXXX', 단건 조회 SELECT문인 경우 'findXXXByPk', 다건 조회 SELECT문인 경우 'findXXXList'가 query id가 된다. 따라서 Naming Rule을 정하고 이에 맞게 query id를 정의하면, 공통되는 기본 문자열만을 사용하여 원하는 쿼리문을 실행할 수 있게 된다.

  • query id 조합을 위한 Prefix, Postfix는 수정이 가능하다.

  • createId(Default='create'), updateId(Default='update'), removeId(Default='remove'), findPrefix(Default='find'), findListPostfix(Default='List'), findByPkPostfix(Default='ByPk') 속성에 대한 setter 메소드를 제공하므로 수정 적용이 가능하다.

  • 입력 Parameter를 VO, Map, List, Object[] 형태에 담아 처리할 수 있다.

  • 입력된 Parameter는 Named Parameter로 처리되기 때문에 VO의 Map, VO의 ArrayList 등에 대한 처리도 가능해진다. 따라서 DAO 코드가 단순해질 수 있게 된다.

  • 단건 데이터 조회 결과 처리를 위해 필요한 공통 로직을 수행한다.

  • Query 서비스의 find(), findBySQL() 메소드를 호출하면 SELECT문 실행 결과를 Collection 객체에 담아 전달한다. 따라서 조회 결과가 따라서 조회 결과가 단건인 경우 Collection으로부터 단건 데이터를 꺼내서 전달하는 로직이 추가되어야 한다.
    if (collection == null || collection.size() == 0)
        return null;
    return collection.iterator().next();
    AbstractDAO에서 제공하는 findByPk(...) 메소드를 호출하면 위에서 언급한 추가 로직을 중복 구현하지 않고 단건 데이터를 얻을 수 있게 된다.

  • UI 개발 편의를 위해서 다건 데이터 조회 결과를 별도의 Page 객체에 저장하는 로직을 수행한다.

  • Query 서비스의 findWithRowCount() 메소드를 호출하면, SELECT문 실행 결과를 Map 객체에 담아 전달하며, 개발자는 UI 개발 편의를 위해 Map 객체로부터 필요한 데이터를 추출하여 별도의 Page 객체에 담기 위한 로직을 추가해야 한다.
    List resultList = (List) queryMap.get(IQueryService.LIST);
    int totalSize = ((Long) queryMap.get(IQueryService.COUNT)).intValue();
    return new Page(resultList, (new Integer(pageIndex)).intValue(),
        totalSize, pageUnit, pageSize);
    AbstractDAO에서 제공하는 findListWithPaging() 메소드를 호출하면 위에서 언급한 추가 로직을 중복 구현하지 않고도 Page 형태의 객체를 얻을 수 있게 된다.

매핑 XML 파일 Sample

다음은 Query 서비스를 통해 로드된 mapping-abstractdao-query.xml 로, Named Parameter를 포함한 다양한 쿼리문들을 포함하고 있다.
<queryservice>
	<queries>
		<query id="findCUSTOMERByPk">
			<statement>
				SELECT * FROM TBL_CUSTOMER WHERE SSNO like :vo.ssno
			</statement>
			<result class="integration.anyframe.services.query.vo.CustomerVO"/>
		</query>	
		<query id="findCUSTOMERList">
			<statement>
				SELECT * FROM TBL_CUSTOMER  WHERE SSNO like :vo.ssno
			</statement>
			<result class="integration.anyframe.services.query.vo.CustomerVO"/>
		</query>		
		<query id="createCUSTOMER">
			<statement>
				INSERT INTO TBL_CUSTOMER ( ssno, name, address ) 
				VALUES (:vo.ssno,:vo.name,:vo.addr)
			</statement>
		</query>		
		<query id="updateCUSTOMER">
			<statement>
				UPDATE TBL_CUSTOMER SET ssno = :vo.ssno , name = :vo.name, 
				  address = :vo.addr WHERE ssno = :vo.ssno
			</statement>
			<result class="integration.anyframe.services.query.vo.CustomerVO"/>
		</query>
		<query id="removeCUSTOMER">
			<statement>
				DELETE FROM TBL_CUSTOMER WHERE ssno = :vo.ssno
			</statement>
			<result class="integration.anyframe.services.query.vo.CustomerVO"/>
		</query>
	</queries>
</queryservice>

DAO 클래스 코드 Sample

다음은 AbstractDAO를 상속받아 구현한 CustomerDAO.java 클래스의 내용이다. AbstractDAO에서 제공하는 메소드를 호출함으로써 Customer 정보를 INSERT, UPDATE, DELETE, SELECT하는 역할을 수행하는 CustomerDAO 로직이 보다 간단해졌음을 알 수 있을 것이다. AbstractDAO 클래스를 상속받은 경우 Query 서비스의 API를 직접 호출하려면 getQueryService() 메소드 호출을 통해 Query 서비스를 얻어내어 활용하도록 한다.
public class CustomerDAO extends AbstractDAO {
	// query id가 'createCUSTOMER'인 INSERT문을 실행
	public int createCustomer(CustomerVO vo) throws Exception {
		return create("CUSTOMER", vo);
	}
	
	// query id가 'deleteCUSTOMER'인 UPDATE문을 실행
	public int deleteCustomer(CustomerVO vo) throws Exception {
		return remove("CUSTOMER", vo);
	}
	
	// query id가 'findCUSTOMERByPk'인 SELECT문을 실행하고 
	// 조회 결과인 CustomerVO 객체를 전달 
	public CustomerVO selectCustomer(String ssno) throws Exception {
		CustomerVO vo = new CustomerVO();
		vo.setSsno(ssno);
		CustomerVO resultVo = (CustomerVO) findByPk("CUSTOMER", vo);
		return resultVo;
	}
	
	// query id가 'findCUSTOMERList'인 SELECT문을 실행하고 
	// 조회 결과인 Page 객체를 전달
	public Page selectCustomerList(CustomerVO vo, int pageIndex, int pageSize,
			int pageUnit) throws Exception {
		return findListWithPaging("CUSTOMER", vo, pageIndex,
				pageSize, pageUnit);
	}
	
	// query id가 'updateCUSTOMER'인 UPDATE문을 실행
	public int updateCustomer(CustomerVO vo) throws Exception {
		return update("CUSTOMER", vo);
	}
}

DAO 클래스 속성 정의 파일 Sample

AbstractDAO 클래스를 상속받은 CustomerDAO 클래스의 속성을 정의한 applicationContext-customer.xml 파일의 일부이다. AbstractDAO 클래스에서 내부적으로 Query 서비스를 사용하므로 Query 서비스의 Bean Id를 속성으로 셋팅해주어야 한다.
<bean id="customerDAO" class="integration.anyframe.services.query.CustomerDAO">
	<property name="queryService" ref="queryService" />
</bean>

DAO 클래스 테스트 코드 Sample

다음은 앞서 언급한 매핑 XML 파일에 정의된 INSERT, SELECT, UPDATE, DELETE 쿼리문을 실행하는 소스 코드 QueryServiceTestAbstractDAO.java 이다.
/**
 * AbstractDAO를 통해 DB에 신규 데이터를 입력하는 테스트 코드
 */
public void testInsertQuery() throws Exception {
	CustomerVO vo1 = new CustomerVO("1234567890123", "AAAAA", "seoul");
	// 매핑 XML 파일에 정의되어 있는 query id를 이용하여 INSERT를 실행한다.
	customerDAO.createCustomer(vo1);
	CustomerVO vo2 = new CustomerVO("2345678901234", "BBBBB", "inchun");
	customerDAO.createCustomer(vo2);
}

/**
 * AbstractDAO를 통해 DB에 입력된 데이터를 조회하는 테스트 코드
 */
public void testSelectQuery() throws Exception {
	String ssno = "1234567890123";
	CustomerVO vo = null;

	// 매핑 XML 파일에 정의되어 있는 query id를 이용하여 SELECT를 실행한다.
	vo = customerDAO.selectCustomer(ssno);
	if (!vo.getSsno().equals(ssno)) {
		throw new Exception("Select query failed");
	}
}

/**
 * AbstractDAO를 통해 DB에 입력된 데이터를 페이징 처리하기 위한 테스트 코드
 */
public void testSelectPagingQuery() throws Exception {
	CustomerVO vo = new CustomerVO("2345678901234", "", "");

	// 매핑 XML 파일에 정의되어 있는 query id를 이용하여 SELECT를 실행하고,
	// 페이징 처리된 실행 결과를 얻는다.
	Page page = customerDAO.selectCustomerList(vo, 1, 2, 10);
	if (page.getSize() != 1) {
		throw new Exception("Select paging query failed");
	}
}

/**
 * AbstractDAO를 통해 DB에 입력된 데이터를 수정하는 테스트 코드
 */
public void testUpdateQuery() throws Exception {
	// 매핑 XML 파일에 정의되어 있는 query id를 이용하여 UPDATE를 실행한다.
	CustomerVO vo = new CustomerVO("1234567890123", "AAAAA", "busan");
	int rs = customerDAO.updateCustomer(vo);

	if (rs == -1) {
		throw new Exception("Update query failed");
	}
}

/**
 * AbstractDAO를 통해 DB에 입력된 데이터를 삭제하는 테스트 코드
 */
public void testDeleteQuery() throws Exception {
	CustomerVO vo = new CustomerVO("1234567890123", "", "");
	// 매핑 XML 파일에 정의되어 있는 query id를 이용하여 DELETE를 실행한다.
	int rs = customerDAO.deleteCustomer(vo);

	if (rs == -1) {
		throw new Exception("Delete query failed");
	}
}
앞서 소개된 샘플 테스트 코드를 포함하여 Query 서비스 소개 페이지에서 제공하는 모든 샘플 테스트 코드는 HSQL DB를 기반으로 실행된다. ( 단, ※ CallableStatement, LOB의 경우는 Oracle 9i, 10g를 기반으로 함. )

Resources

  • 다운로드
  • 샘플 테스트 코드를 포함하고 있는 anyframe-querytest-src.zip 파일을 다운받은 후, 테스트 환경 설정 을 참조하여 위에서 제시한 예제 코드를 실행해 볼 수 있다.
    Name
    Download
    anyframe-querytest-src.zip
    Download