데이터 오브젝트/데이터 오브젝트 팩토리 개발
본 장에서는 데이터 오브젝트와 데이터 오브젝트 팩토리의 개념과 특징, 개발 방법에 대해 설명한다.
1. 개요
데이터 오브젝트(DataObject, DO)는 ProObject 모듈간 데이터 전달의 기본 단위이며, 서비스 오브젝트의 입출력의 정해진 형식이다.
데이터 오브젝트 팩토리(DataObjectFactory, DOF)는 ProObject에서 DB와 FILE IO 작업을 담당하는 모듈이다. DBIO는 DB 데이터 오브젝트 팩토리를 통해 동작하고, FILEIO는 파일 데이터 오브젝트 팩토리를 통해 개발할 수 있다. 각각의 팩토리는 기반이 되는 데이터 오브젝트가 존재하며, 팩토리는 데이터 오브젝트에 1대1로 매핑하여 개발한다. 데이터 오브젝트 팩토리는 DB 데이터 오브젝트 팩토리와 파일 데이터 오브젝트 팩토리로 나뉜다.
2. 환경설정
데이터 오브젝트 및 데이터 오브젝트 팩토리와 관련된 옵션은 ProManager를 통해 아래 파일에 설정된다.
2.1. 시스템 설정
ProObject 엔진의 가장 기본적인 설정은 다음의 파일에 Key-Value 방식을 이용해 설정한다.
${PROOBJECT_HOME}/config/system.properties
다음은 system.properties의 설정항목에 대한 설명이다.
SYSTEM_DATAOBJECT_QUERY_LOGGING = [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF] SYSTEM_DATAOBJECT_CONFIG_LOG_LEVEL = [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF] SYSTEM_DATAOBJECT_BANNED_PARAMETER = parmeter1,parameter2.... SYSTEM_DATAOBJECT_DEFAULT_PAGE_SIZE = page_size SYSTEM_DATAOBJECT_MAX_PAGE_SIZE = max_page_size SYSTEM_DATAOBJECT_PAGE_QUERY = page_query SYSTEM_DATAOBJECT_PAGE_HINT = page_hint SYSTEM_DATAOBJECT_DEFAULT_CACHE_SIZE = cache_size SYSTEM_DATAOBJECT_MAX_ROW_SIZE = max_row_size SYSTEM_DATAOBJECT_LIMIT_ROW_SIZE = [true|false] SYSTEM_DATAOBJECT_THROW_MAX_ROW_EXCEPTION = [true|false] SYSTEM_DATAOBJECT_SINGLE_RESULT_CHECK = [true|false] SYSTEM_DATAOBJECT_EMPTY_RESULT_CHECK = [true|false] SYSTEM_DATAOBJECT_EMPTY_RESULT_CHECK_FOR_UPDATE = [true|false] SYSTEM_DATAOBJECT_FETCH_SIZE = fatch_size SYSTEM_DATAOBJECT_BATCH_MAX_SIZE = batch_max_size SYSTEM_DATAOBJECT_SECOND_CACHE = second_cache_class SYSTEM_DATAOBJECT_CACHE_ENABLE = [true|false] SYSTEM_MESSAGE_FLD_MARSHAL_NUMBER_FILL_TYPE = [zero|space] SYSTEM_MESSAGE_FLD_UNMARSHAL_NUMBER_FILL_TYPE = [zero|space] SYSTEM_FILE_DATAOBJECT_CHARSET = [UTF-8|EUC-KR]
항목 | 설명 |
---|---|
SYSTEM_DATAOBJECT_QUERY_LOGGING |
데이터 오브젝트 팩토리가 수행한 쿼리를 로깅할 로그 레벨을 지정한다. 쿼리는 서비스 로그에 남는다. ProObject에 설정된 엔진 로그 설정과 비교하여 쿼리 로깅 레벨이 엔진 로거의 로그 레벨보다 같거나 더 높은 경우 로깅한다. 다음 중에 설정한다.
|
SYSTEM_DATAOBJECT_CONFIG_LOG_LEVEL |
데이터 오브젝트 팩토리에 설정된 옵션값들을 로깅할 로그 레벨을 지정한다. ProObject에 설정된 엔진 로그 설정과 비교하여 설정 로깅 레벨이 엔진 로거의 로그 레벨보다 같거나 더 높은 경우 로깅한다. 다음 중에 설정한다.
|
SYSTEM_DATAOBJECT_BANNED_PARAMETER |
데이터 오브젝트 팩토리가 쿼리를 수행할 때 파라미터 값으로 들어오면 안되는 금칙어를 설정한다. 금칙어 목록은 콤마(,)를 구분자로 구분하여 연속해서 입력한다. |
SYSTEM_DATAOBJECT_DEFAULT_PAGE_SIZE |
DB 데이터 오브젝트 팩토리가 제공하는 페이징 기능을 사용할 때 한 페이지에 담을 데이터 수를 지정한다. (기본값: 10) |
SYSTEM_DATAOBJECT_MAX_PAGE_SIZE |
SYSTEM_DATAOBJECT_DEFAULT_PAGE_SIZE 옵션값으로 지정할 수 있는 최대 페이지 수를 제한한다. 해당 옵션 값이 0인 경우 이 옵션은 동작하지 않는다. (기본값: 0) |
SYSTEM_DATAOBJECT_PAGE_QUERY |
페이징 처리를 하는 경우 사용할 페이징 쿼리문을 입력한다. ProObject은 기본으로 Oracle과 Tibero에서 사용할 수 있는 페이징 쿼리를 제공한다. 사용하는 DBMS가 Tibero나 Oracle이 아닌 경우 본 옵션에 페이징 처리를 위한 쿼리를 입력한다. (기본값: Tibero, Oracle 기준 페이징 처리법) |
SYSTEM_DATAOBJECT_PAGE_HINT |
DB 데이터 오브젝트 팩토리에서 페이징 처리를 하는 경우 쿼리 옵티마이저 힌트를 설정한다. (기본값: EMPTY String) |
SYSTEM_DATAOBJECT_DEFAULT_CACHE_SIZE |
ProObject에서 제공하는 세션 캐시를 사용하는 경우 캐시 크기를 지정한다. (기본값: 5000) |
SYSTEM_DATAOBJECT_MAX_ROW_SIZE |
DB 데이터 오브젝트 팩토리를 이용하여 다건 조회하는 경우 조회 가능한 최대 건수를 설정한다. 입력 값이 음수인 경우 기본값으로 동작한다. (기본값: 0) |
SYSTEM_DATAOBJECT_LIMIT_ROW_SIZE |
SYSTEM_DATAOBJECT_MAX_ROW_SIZE 옵션의 제한값을 적용할지 여부를 설정한다.
|
SYSTEM_DATAOBJECT_THROW_MAX_ROW_EXCEPTION |
SYSTEM_DATAOBJECT_MAX_ROW_SIZE에서 적용한 값을 넘어서는 데이터를 조회할 때 Exception이 발생한다.
|
SYSTEM_DATAOBJECT_SINGLE_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get() API를 이용하여 단건 조회를 수행하는 경우 조회 결과가 2건 이상인 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다. |
SYSTEM_DATAOBJECT_EMPTY_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get, getForwardList, getScrollableList, getDataObjectList를 통해 데이터를 조회할 때 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
SYSTEM_DATAOBJECT_EMPTY_RESULT_CHECK_FOR_UPDATE |
DB 데이터 오브젝트 팩토리의 add, update, remove를 통해 데이터 추가, 갱신, 삭제를 할 때 반영된 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
SYSTEM_DATAOBJECT_FETCH_SIZE |
DB 데이터 오브젝트 팩토리에서 조회 쿼리를 수행하는 경우 조회할 페치(FETCH) 크기를 지정한다. 옵션값은 java.sql.PreparedStatement의 setFecthSize()를 통해 설정한다. (기본값: 300) |
SYSTEM_DATAOBJECT_BATCH_MAX_SIZE |
DB 데이터 오브젝트 팩토리의 addBatch 기능을 사용할 경우 addBatch가 가능한 최대 건수를 설정한다. 해당 갯수만큼 addBatch가 쌓이면 자동으로 executeBatch를 수행한다. (기본값: 0) |
SYSTEM_DATAOBJECT_SECOND_CACHE |
2차 캐시를 핸들링할 com.tmax.proobject.dataobject.cache.IProObjectCacheManager 인터페이스를 구현한 클래스를 입력한다. Tmax의 InfiniCache를 2차 캐시로 사용할 경우 com.tmax.proobject.dataobject.cache.InfiniCacheManager를 값으로 설정한다. |
SYSTEM_DATAOBJECT_CACHE_ENABLE |
캐시 기능을 ON/OFF하기 위한 설정이다. 이 옵션값이 true에서 false로 변경되면 캐시 영역을 invalidate한다.
해당 옵션은 반드시 SYSTEM_DATAOBJECT_SECOND_CACHE와 APPLICATION_DATAOBJECT_CACHE 설정과 함께 사용해야 한다. |
SYSTEM_MESSAGE_FLD_MARSHAL_NUMBER_FILL_TYPE |
데이터 오브젝트를 메시지화할 경우 숫자 타입의 필드의 여백을 무엇으로 채울지에 대한 옵션이다.
|
SYSTEM_MESSAGE_FLD_UNMARSHAL_NUMBER_FILL_TYPE |
ProObject가 받은 메시지를 데이터 오브젝트화할 경우 숫자 타입문자의 여백을 인식하는 방법을 설정한다.
|
SYSTEM_FILE_DATAOBJECT_CHARSET |
파일 데이터 오브젝트 팩토리를 이용하여 파일을 쓰는 경우 사용할 CharSet을 지정한다. 다음 중에 하나를 설정한다.
|
2.2. 애플리케이션 설정
ProObject 엔진의 가장 기본적인 설정은 다음의 파일에 Key-Value 방식을 이용해 설정한다.
${APP_HOME}/config/application.properties
다음은 application.properties의 설정항목에 대한 설명이다.
APPLICATION_DATAOBJECT_CACHE = dataobject_cache APPLICATION_DATAOBJECTFACTORY_QUERY_LOGGING_LEVEL = [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF] APPLICATION_DATAOBJECT_CONFIG_LOG_LEVEL = [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF] APPLICATION_DATAOBJECTFACTORY_DEFAULT_PAGE_SIZE = page_size APPLICATION_DATAOBJECTFACTORY_PAGE_HINT = paging_query_hint APPLICATION_DATAOBJECTFACTORY_MAX_ROW_SIZE = maximum_row_number APPLICATION_DATAOBJECTFACTORY_LIMIT_ROW_SIZE = [true|false] APPLICATION_DATAOBJECTFACTORY_THROW_MAX_ROW_EXCEPTION = [true|false] APPLICATION_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK = [true|false] APPLICATION_DATAOBJECTFACTORY_FETCH_SIZE = fetch_size APPLICATION_DATAOBJECTFACTORY_QUERY_TIMEOUT = query_timeout APPLICATION_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK = [true|false] APPLICATION_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK_FOR_UPDATE = [true|false] APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE = [true|false] APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH = encryptmodule_class APPLICATION_DATAOBJECTFACTORY_ENCRYPT_TYPE = [AES256|SEED128]
항목 | 설명 |
---|---|
APPLICATION_DATAOBJECT_CACHE |
캐시 기능을 사용할 데이터 오브젝트 팩토리 리스트를 지정한다. 데이터 오브젝트 팩토리 캐시 기능은 애플리케이션의 데이터 오브젝트 팩토리별로 ON/OFF가 가능하며, 리스트는 콤마(,)을 통해 구분한다. (기본값: EMPTY String) |
APPLICATION_DATAOBJECTFACTORY_QUERY_LOGGING_LEVEL |
데이터 오브젝트 팩토리가 실행한 쿼리문을 출력하는 로그 레벨을 지정한다. ProObject에 설정된 엔진 로그 설정과 비교하여 쿼리 로깅 레벨이 엔진 로거의 로그 레벨보다 같거나 더 높은 경우 로깅한다. 다음 중에 설정한다.
|
APPLICATION_DATAOBJECT_CONFIG_LOG_LEVEL |
데이터 오브젝트 팩토리가 사용 중인 옵션 값들을 출력하는 로그 레벨을 지정한다. 다음 중에 설정한다.
|
APPLICATION_DATAOBJECTFACTORY_DEFAULT_PAGE_SIZE |
다건 조회하는 경우 DB 데이터 오브젝트 팩토리가 조회할 페이지의 기본 사이즈를 지정한다. (기본값: 10) |
APPLICATION_DATAOBJECTFACTORY_PAGE_HINT |
다건 조회하는 경우 페이징 기능을 사용할 경우 페이징 쿼리에 포함할 쿼리 힌트를 지정한다. |
APPLICATION_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get() API를 이용하여 단건 조회를 수행하는 경우 조회 결과가 2건 이상인 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다. |
APPLICATION_DATAOBJECTFACTORY_FETCH_SIZE |
DB 데이터 오브젝트 팩토리에서 조회 쿼리를 수행하는 경우 조회할 페치 크기를 지정한다. 옵션값은 java.sql.PreparedStatement의 setFecthSize()를 통해 설정한다. (기본값: 300) |
APPLICATION_DATAOBJECTFACTORY_QUERY_TIMEOUT |
DB 데이터 오브젝트 팩토리가 쿼리를 수행할 때의 타임아웃을 지정한다. 옵션값은 java.sql.PreparedStatement의 setQueryTimeout()을 통해 설정한다. 설정하지 않는 경우 데이터소스를 제공하는 WAS의 쿼리 타임아웃 설정을 따른다. (기본값: 0, 단위: second) |
APPLICATION_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get, getForwardList, getScrollableList, getDataObjectList를 통해 데이터를 조회할 때 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
APPLICATION_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK_FOR_UPDATE |
DB 데이터 오브젝트 팩토리의 add, update, remove를 통해 데이터 추가, 갱신, 삭제를 할 때 반영된 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE |
DB 데이터 오브젝트 팩토리의 데이터 오브젝트 멤버변수 암호화 기능을 ON/OFF하기 위한 설정값이다. |
APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH |
데이터 오브젝트 멤버변수를 암호화하는 경우 사용할 클래스 패스를 지정한다(com.tmax.proobject.dataobject.security.IEncryptUtil을 상속받은 클래스로 지정한다). |
APPLICATION_DATAOBJECT_FACTORY_ENCRYPT_TYPE |
APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH 설정을 통해 따로 암호화모듈의 클래스 패스를 지정하지 않은 경우 ProObject에서 제공하는 기본 암호화 알고리즘을 사용할수 있다. 사용 가능한 기본 알고리즘은 'AES256’과 'SEED128' 두 가지가 있다. 이 두 알고리즘이외의 알고리즘을 사용하려면 알고리즘을 구현한 구현체를 APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH 설정을 통해 지정해야 한다. |
APPLICATION_DATAOBJECTFACTORY_MAX_ROW_SIZE |
DB 데이터 오브젝트 팩토리를 이용하여 다건 조회하는 경우 조회 가능한 최대 건수를 설정한다. 입력 값이 음수인 경우 기본값으로 동작한다. (기본값: 0) |
APPLICATION_DATAOBJECTFACTORY_LIMIT_ROW_SIZE |
APPLICATION_DATAOBJECTFACTORY_MAX_ROW_SIZE 옵션의 제한값을 적용할지 여부를 설정한다.
|
APPLICATION_DATAOBJECTFACTORY_THROW_MAX_ROW_EXCEPTION |
APPLICATION_DATAOBJECTFACTORY_MAX_ROW_SIZE에서 적용한 값을 넘어서는 데이터를 조회할 때Exception이 발생한다.
|
2.3. 서비스 그룹 설정
ProObject 엔진의 가장 기본적인 설정은 다음의 파일에 Key-Value 방식을 이용해 설정한다.
${SG_HOME}/config/servicegroup.properties
다음은 servicegroup.properties의 설정항목에 대한 설명이다.
SERVICEGROUP_DATAOBJECTFACTORY_QUERY_LOGGING_LEVEL = [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF] SERVICEGROUP_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK = [true|false] SERVICEGROUP_DATAOBJECTFACTORY_QUERY_TIMEOUT = query_timeout SERVICEGROUP_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK = [true|false] SERVICEGROUP_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK_FOR_UPDATE = [true|false] SERVICEGROUP_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK = [true|false] SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE = [true|false] SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH = encryptmodule_class SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPT_TYPE = [AES256|SEED128] SERVICEGROUP_DATAOBJECTFACTORY_MAX_ROW_SIZE = maximum_row_number SERVICEGROUP_DATAOBJECTFACTORY_LIMIT_ROW_SIZE = [true|false] SERVICEGROUP_DATAOBJECTFACTORY_THROW_MAX_ROW_EXCEPTION = [true|false]
항목 | 설명 |
---|---|
SERVICEGROUP_DATAOBJECTFACTORY_QUERY_LOGGING_LEVEL |
데이터 오브젝트 팩토리가 실행한 쿼리문을 출력하는 로그 레벨을 지정한다. ProObject에 설정된 엔진 로그 설정과 비교하여 쿼리 로깅 레벨이 엔진 로거의 로그 레벨보다 같거나 더 높은 경우 로깅한다. 다음 중에 설정한다.
|
SERVICEGROUP_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get() API를 이용하여 단건 조회를 수행하는 경우 조회 결과가 2건 이상인 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다. |
SERVICEGROUP_DATAOBJECTFACTORY_QUERY_TIMEOUT |
DB 데이터 오브젝트 팩토리가 쿼리를 수행할 때 타임아웃을 지정한다. 옵션값은 java.sql.PreparedStatement의 setQueryTimeout()을 통해 설정한다. 설정하지 않는 경우 데이터소스를 제공하는 WAS의 쿼리 타임아웃 설정을 따른다. (기본값: 0, 단위: second) |
SERVICEGROUP_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get, getForwardList, getScrollableList, getDataObjectList를 통해 데이터를 조회하는 조회할 때 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
SERVICEGROUP_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK_FOR_UPDATE |
DB 데이터 오브젝트 팩토리의 add, update, remove를 통해 데이터 추가, 갱신, 삭제를 할 때 반영된 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE |
DB 데이터 오브젝트 팩토리의 데이터 오브젝트 멤버변수 암호화 기능을 ON/OFF하기 위한 설정값이다. |
SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH |
데이터 오브젝트 멤버변수를 암호화하는 경우 사용할 클래스 패스를 지정한다(com.tmax.proobject.dataobject.security.IEncryptUtil을 상속받은 클래스로 지정한다). |
SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPT_TYPE |
SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH 설정을 통해 따로 암호화모듈의 클래스 패스를 지정하지 않은 경우 ProObject에서 제공하는 기본 암호화 알고리즘을 사용할수 있다. 사용 가능한 기본 알고리즘은 'AES256’과 'SEED128' 두 가지가 있다. 이 두 알고리즘 이외의 알고리즘을 사용하려면 알고리즘을 구현한 구현체를 SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH 설정을 통해 지정해야 한다. |
SERVICEGROUP_DATAOBJECTFACTORY_MAX_ROW_SIZE |
DB 데이터 오브젝트 팩토리를 이용하여 다건 조회하는 경우 조회 가능한 최대 건수를 설정한다. 입력 값이 음수인 경우 기본값으로 동작한다. (기본값: 0) |
SERVICEGROUP_DATAOBJECTFACTORY_LIMIT_ROW_SIZE |
SERVICEGROUP_DATAOBJECTFACTORY_MAX_ROW_SIZE 옵션의 제한값을 적용할지 여부를 설정한다.
|
SERVICEGROUP_DATAOBJECTFACTORY_THROW_MAX_ROW_EXCEPTION |
SERVICEGROUP_DATAOBJECTFACTORY_MAX_ROW_SIZE에서 적용한 값을 넘어서는 데이터를 조회할 때Exception이 발생한다.
|
2.4. 서비스 설정
ProObject 엔진의 서비스 설정은 서비스 그룹과 동일하게 servicegroup.properties에 Key-Value 방식으로 설정한다.
${SG_HOME}/config/servicegroup.properties
다음은 servicegroup.properties의 설정항목에 대한 설명이다.
SERVICE_{0}_DATAOBJECTFACTORY_QUERY_LOGGING_LEVEL = [SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF] SERVICE_{0}_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK = [true|false] SERVICE_{0}_DATAOBJECTFACTORY_QUERY_TIMEOUT = query_timeout SERVICE_{0}_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK = [true|false] SERVICE_{0}_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK_FOR_UPDATE = [true|false] SERVICE_{0}_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE = [true|false] SERVICE_{0}_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH = encryptmodule_class SERVICE_{0}_DATAOBJECTFACTORY_ENCRYPT_TYPE = [AES256|SEED128] SERVICE_{0}_DATAOBJECTFACTORY_MAX_ROW_SIZE = maximum_row_number SERVICE_{0}_DATAOBJECTFACTORY_LIMIT_ROW_SIZE = [true|false] SERVICE_{0}_DATAOBJECTFACTORY_THROW_MAX_ROW_EXCEPTION = [true|false]
항목 | 설명 |
---|---|
SERVICE_{0}_DATAOBJECTFACTORY_QUERY_LOGGING_LEVEL |
데이터 오브젝트 팩토리가 실행한 쿼리문을 출력하는 로그 레벨을 지정한다. ProObject에 설정된 엔진 로그 설정과 비교하여 쿼리 로깅 레벨이 엔진 로거의 로그 레벨보다 같거나 더 높은 경우 로깅한다. 다음 중에 설정한다.
|
SERVICE_{0}_DATAOBJECTFACTORY_SINGLE_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get() API를 이용하여 단건 조회를 수행하는 경우 조회 결과가 2건 이상인 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다. |
SERVICE_{0}_DATAOBJECTFACTORY_QUERY_TIMEOUT |
DB 데이터 오브젝트 팩토리가 쿼리를 수행할 때 타임아웃을 지정한다. 옵션값은 java.sql.PreparedStatement의 setQueryTimeout()을 통해 설정한다. 설정하지 않는 경우 데이터소스를 제공하는 WAS의 쿼리 타임아웃 설정을 따른다. (기본값: 0, 단위: second) |
SERVICE_{0}_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK |
DB 데이터 오브젝트 팩토리의 get, getForwardList, getScrollableList, getDataObjectList를 통해 데이터를 조회하는 조회할 때 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
SERVICE_{0}_DATAOBJECTFACTORY_EMPTY_RESULT_CHECK_FOR_UPDATE |
DB 데이터 오브젝트 팩토리의 add, update, remove를 통해 데이터 추가, 갱신, 삭제를 할 때 반영된 결과가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다. |
SERVICE_{0}_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE |
DB 데이터 오브젝트 팩토리의 데이터 오브젝트 멤버변수 암호화 기능을 ON/OFF하기 위한 설정값이다. |
SERVICE_{0}_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH |
데이터 오브젝트 멤버변수를 암호화하는 경우 사용할 클래스 패스를 지정한다(com.tmax.proobject.dataobject.security.IEncryptUtil을 상속받은 클래스로 지정한다). |
SERVICE_{0}_DATAOBJECTFACTORY_ENCRYPT_TYPE |
SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH 설정을 통해 따로 암호화모듈의 클래스 패스를 지정하지 않은 경우 ProObject에서 제공하는 기본 암호화 알고리즘을 사용할수 있다. 사용 가능한 기본 알고리즘은 'AES256’과 'SEED128' 두 가지가 있다. 이 두 알고리즘이외의 알고리즘을 사용하려면 알고리즘을 구현한 구현체를 SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_PATH 설정을 통해 지정해야 한다. |
SERVICE_{0}_DATAOBJECTFACTORY_MAX_ROW_SIZE |
DB 데이터 오브젝트 팩토리를 이용하여 다건 조회하는 경우 조회 가능한 최대 건수를 설정한다. 입력 값이 음수인 경우 기본값으로 동작한다. (기본값: 0) |
SERVICE_{0}_DATAOBJECTFACTORY_LIMIT_ROW_SIZE |
SERVICE_{0}_DATAOBJECTFACTORY_MAX_ROW_SIZE 옵션의 제한값을 적용할지 여부를 설정한다.
|
SERVICE_{0}_DATAOBJECTFACTORY_THROW_MAX_ROW_EXCEPTION |
SERVICE_{0}_DATAOBJECTFACTORY_MAX_ROW_SIZE에서 적용한 값을 넘어서는 데이터를 조회할 때Exception이 발생한다.
|
3. 데이터 오브젝트
데이터 오브젝트(DataObject)는 ProObject 모듈간 데이터 전달의 기본 단위이며, 서비스 오브젝트의 입출력의 정해진 형식이다. 데이터 오브젝트는 ProManager를 통해 등록한 메타 데이터를 기반으로 ProStudio에서 개발할 수 있으며, 자세한 내용은 ProObject Studio 개발자 안내서를 참고한다.
3.1. 개발 방법
데이터 오브젝트를 개발하기 위해서는 메타 딕셔너리에 개발자가 사용할 메타 데이터가 등록되어 있어야 한다.
ProStudio의 데이터 오브젝트 에디터를 통해 메타 딕셔너리에서 사용할 메타 데이터를 검색하여 데이터 오브젝트의 멤버변수를 구성한다. 데이터 오브젝트의 멤버변수로 선언할 수 있는 메타의 Java Type은 int, long, float, double, short, byte, boolean, char 8가지 primitive type과 각 primitive type에 대한 wrapper class을 포함하는 BigInteger, BigDecimal, Date, Timestamp, Blob, Clob과 같은 java.sql type도 지원한다.
데이터 오브젝트의 개발 과정은 다음과 같다.
-
ProManager를 통해서 메타 딕셔너리를 구성한다.
-
ProStudio를 통해서 데이터 오브젝트를 생성한다.
-
ServiceObject, BizObject 등에 데이터 오브젝트를 사용하여 개발한다.
데이터 오브젝트는 기본적으로 멤버변수와 자신의 변수 타입에 대한 Getter/ Setter를 메소드뿐 아니라 부수적인 기능을 갖고 있다.
다음은 데이터 오브젝트의 개발에 사용되는 변수와 주요 기능에 대한 설명이다.
-
부모 데이터 오브젝트
데이터 오브젝트는 다른 데이터 오브젝트를 자신의 부모 클래스로 지정할 수 있다. 개발된 데이터 오브젝트는 개발자가 지정한 부모 클래스를 extends한 형태로 생성된다. 이때 데이터 오브젝트의 부모 클래스로는 데이터 오브젝트 밖에 지정할 수 없으므로 다른 클래스를 부모 클래스로 지정하지 않도록 주의한다.
-
Include 데이터 오브젝트
데이터 오브젝트는 위에서 설명한 8가지 primitive type과 그에 대한 wrapper type, java.sql type 외에도 다른 데이터 오브젝트를 멤버변수로 갖을 수 있다. 개발 방법은 메타 딕셔너리에 메타 데이터를 검색하는 것과 동일하게, ProStudio에서 데이터 오브젝트를 검색하여 메타처럼 활용하여 개발한다. 이때 Super 데이터 오브젝트와 마찬가지로 데이터 오브젝트외에 다른 클래스를 멤버변수로 선언하지 않도록 주의해야 한다.
-
마스킹
String 타입의 멤버변수인 경우 마스크(mask)를 지정할 수 있다. 마스킹은 데이터 오브젝트를 메시지로 변환하거나, toString 등으로 멤버변수의 값을 출력할 경우 변수의 값을 마스크 값으로 치환하는 기능이다. 예를 들어 'name' 변수에 마스킹 옵션이 지정되어 있으면 데이터 오브젝트의 toString API를 호출하는 경우 'name’의 값이 '****'와 같이 표시된다.
마스크 옵션 지정은 메타를 통해서 지정되며, 마스크 옵션이 설정된 메타를 이용하여 데이터 오브젝트의 멤버변수를 선언한 경우 해당 멤버변수는 마스킹이 지정된다.
마스킹이 설정된 멤버변수의 경우 마스킹된 데이터를 받아올수 있는 Getter API가 추가된다.
마스킹 인덱스는 0부터 시작하며, 단일 인덱스 / 범위 인덱스방식으로 마스킹 범위를 지정할수 있다.
-
단일 인덱스 : 마스킹하고자 하는 위치의 인덱스를 지정합니다. 문자열의 제일 첫 인덱스는 0부터 시작합니다.
-
범위 인덱스 : '-' 문자를 통해서 마스킹하고자 하는 인덱스의 범위를 From ~ To 로 지정합니다.
From만 입력하는 경우 : '0 - ' 0번 인덱스부터 문자열끝까지 마스킹한다. To만 입력하는 경우 : '- 10' 0번 인덱스부터 10번 인덱스까지 마스킹한다. From-To 로 입력하는 경우 : '0-5' 0번 인덱스부터 5번 인덱스까지 마스킹한다.
-
마스킹 범위의 구분 : 마스킹 범위는 다중으로 지정 가능하며 ','를 통해 각 범위를 구분한다.
'-2,4,6-7,9-' 1. 0번 인덱스부터 2번 인덱스까지 마스킹 2. 4번 인덱스 마스킹 3. 6번 인덱스부터 7번 인덱스까지 마스킹 4. 9번 인덱스부터 문자열끝까지 마스킹
-
-
메시지
데이터 오브젝트는 ProStudio를 통해서 JSON, FixedLength, Delimiter, XML 형식의 전문을 지원하는 메시지 클래스를 생성하여 사용할 수 있다.
구분 설명 JSON
메시지 전문 형태를 JSON으로 주고받는다.
FixedLength
메시지 전문 형태를 메타에 지정된 length로 주고받는다. 남는 길이의 경우 임의의 문자로 채워지며 이를 원하지 않을 경우 ProStudio에서 'fill' 문자를 채워넣거나 trim 옵션을 지정할 수 있다. 또한 align, decimal, decimalAlign 옵션을 지정하여 잘리는 방향 및 기준을 설정할 수 있다.
Delimiter
개발자가 지정한 특정 문자로 값들을 구분하여 전문을 주고받는다.
XML
xml 형태로 전문을 주고받는다.
데이터 오브젝트는 기본적인 Java의 primitive 타입 뿐만 아니라, Parent Class 지정 및 다른 DO를 멤버변수로 선언하여 사용할 수 있다.
-
데이터 오브젝트 멤버변수
데이터 오브젝트의 멤버변수는 ProManager를 통해 등록한 메타 데이터를 기반으로 생성된다. 멤버변수는 private으로 선언되며, 멤버변수에 해당하는 Getter와 Setter가 같이 생성된다. 추가적으로 멤버변수마다 '~_nullable', '~_modified' 변수와 해당 필드의 Getter가 생성된다.
-
DTO_LOGICAL_NAME
데이터 오브젝트를 생성하는 경우 개발자가 지정한 논리명을 갖고 있는 String 변수이다.
-
~_nullable 변수
필드의 null 값 허용 여부를 나타내는 변수이다. 이 필드는 private으로 선언되며, Getter만 제공된다.
예를 들어 'number’라는 변수의 Java 타입이 Integer이고 null 값을 허용한다면, number_nullable 변수의 값은 true가 되며 개발자가 isNullableNumber() api를 호출하면 리턴 값은 true가 된다. 데이터 오브젝트를 사용하는 경우 사용할 멤버변수가 null 값을 허용하는지 여부를 확인할 때 사용한다.
-
~_isModified 변수
멤버변수의 Setter 호출 여부를 나타내는 변수이다. 개발자는 isModified~() API를 통해 데이터 오브젝트의 멤버변수의 값이 변경되었는지 확인할 수 있다.
데이터 오브젝트 개발 중 멤버변수의 Setter를 호출하여 변수 값을 변경할 경우 ~_isModified 변수의 값이 true로 변경된다. ~_isModified 변수에 대한 기능은 각 멤버변수의 isModified~() 외에도 isModified()와 getIsModifiedField()를 통해 확인할 수 있다.
-
fieldPropertyMap
데이터 오브젝트의 멤버변수에 해당하는 메타 정보를 저장하고 있는 맵(Map)이다. 맵은 멤버변수명을 key로 하고, 메타 정보를 담고 있는 FieldProperty를 value로 구성된다.
FieldProperty에는 다음과 같은 정보가 담겨 있다.
구분 설명 logicalName
변수의 논리명이다.
Java Type
변수의 java 타입이다.
length
변수의 길이이다.
decimal
float, double, BigDecimal type인 경우 decimal 값이다.
array
변수가 array 타입인 경우 배열의 크기이다.
reference
변수가 include 타입인 경우 멤버변수로 선언된 데이터 오브젝트의 풀 패키지명이다.
columnName
persistence 메타를 사용한 경우 메타에 해당하는 DB 컬럼 이름이다.
tableName
persistence 메타를 사용한 경우 메타에 해당하는 DB 테이블 이름이다.
schema
persistence 메타를 사용한 경우 메타에 해당하는 DB 스키마 이름이다.
key
persistence 메타를 사용한 경우 DB의 key에 해당하는 필드인지 여부이다.
transient
데이터 오브젝트 팩토리를 통해 DB 결과를 DO로 리턴받을 때 DB 작업에서 제외할 필드 여부를 지정한다.
encrypt
데이터 오브젝트 팩토리를 통해 DB 작업을 수행할 경우 해당 멤버변수값을 암호화할지 여부를 지정한다.
3.2. 데이터 오브젝트 API
데이터 오브젝트는 자신의 멤버변수에 해당하는 Getter/Setter 이외에도, 개발의 편의성을 위해 clone, equals, hashCode toString를 제공한다.
API | 설명 |
---|---|
멤버변수 Getter |
데이터 오브젝트를 생성하는 경우 개발자가 지정했던 멤버변수의 값을 반환한다. 멤버변수의 nullable 속성이 false인 경우 null 대신 각 JAVA 타입에 해당하는 기본값이 반환된다.
단, Java 메모리 문제상 String과 byte[]의 경우 최대 64kb 사이즈까지의 값만 지원하고, 반환할 값이 64kb를 넘는 경우 BufferOverflowException이 발생한다. |
멤버변수 Setter |
데이터 오브젝트의 멤버변수에 값을 지정할 때 사용되는 메소드이다. 기본적으로 자기 자신의 타입을 입력받는 Setter외에도, String으로 입력받는 Setter가 추가 지원된다. 그 외에도 BigDecimal이나 BigInteger와 같이 특수한 타입에 대해서는 int, float, double, long, String 등 자기 자신이 아닌 타입의 값을 입력받아서 데이터 오브젝트 내부에서 적절한 값으로 변경하여 저장하는 Setter를 지원한다. |
clone |
현재 데이터 오브젝트가 갖고 있는 멤버변수의 값을 그대로 복사한 데이터 오브젝트를 반환하는 메소드이다. 데이터 오브젝트의 레퍼런스 복사가 아니라 추가적인 객체를 생성하여 값을 복사한 다음 반환한다. |
equals |
데이터 오브젝트의 객체 비교를 위해 제공되는 메소드이다. 데이터 오브젝트의 멤버변수값을 비교하여 동일성을 비교하여 동일 여부를 boolean 값으로 반환한다. |
hashCode |
데이터 오브젝트의 객체 비교를 위해 제공되는 메소드이다. 데이터 오브젝트의 멤버변수값들을 이용하여 hashCode를 생성한 후 반환한다. |
get |
데이터 오브젝트의 멤버변수명을 입력받아 해당하는 멤버변수의 값을 반환하는 메소드이다. |
set |
데이터 오브젝트의 멤버변수명과 값을 입력받아 해당하는 멤버변수에 입력받은 값을 설정하는 메소드이다. |
clear |
데이터 오브젝트의 멤버변수 값들을 초기값으로 설정한다. |
toString |
현재 멤버변수들의 값을 String 값으로 출력한다. 다음의 형태로 출력된다. 출력할 멤버변수에 마스킹 속성이 설정된 경우 마스킹된 값으로 출력된다. '변수명 : + 값' |
3.3. 맵 데이터 오브젝트
맵 데이터 오브젝트(MapDataObject)는 메타를 통한 멤버변수 선언 없이 사용하기 위한 데이터 오브젝트이다. 해당 클래스는 com.tmax.proobject.dataobject에 존재하며, com.tmax.proobject.dataobject.context.ContextDataObject를 상속받아 구현된다.
다음은 오브젝트 사용에 주의할 사항이다.
-
필드명은 NULL이 될수 없다.
-
맵 데이터 오브젝트의 변수에는 기본적인 Java 타입 값과 데이터 오브젝트만 설정할 수 있다.
-
메시지 타입은 com.tmax.proobject.dataobject.MapDataObjectMsgJson 클래스를 통한 JSON 형태만 지원 가능하다.
-
JSON 형태의 메시지를 맵 데이터 오브젝트로 Unmarshal하는 경우 Object type은 맵 데이터 오브젝트, 숫자는 Number, 문자열은 String, true, false는 Boolean, NULL로 변환하여 제공된다.
맵 데이터 오브젝트는 ContextDataObject를 상속받고 있으므로 본 절에서는 맵 데이터 오브젝트에서만 제공하는 API와 오버라이드한 API에 대해서 설명한다.
사용방법은 ContextDataObject와 동일하며 사용 가능한 API는 다음과 같다.
API | 설명 |
---|---|
clone |
현재 데이터 오브젝트가 갖고 있는 멤버변수의 값을 그대로 복사한 데이터 오브젝트를 반환하는 메소드이다. 데이터 오브젝트의 레퍼런스 복사가 아니라 추가적인 객체를 생성하여 값을 복사한 다음 반환한다. |
get |
데이터 오브젝트의 멤버변수명을 입력받아 해당하는 멤버변수의 값을 반환하는 메소드이다. |
set |
데이터 오브젝트의 멤버변수명과 값을 입력받아 멤버변수에 값을 설정하는 메소드이다. 필드명은 NULL이 될 수 없다. |
setIfAbsent |
데이터 오브젝트에 입력받은 필드명에 해당하는 값이 없는 경우에만 데이터를 추가한다. 반환값은 입력받은 필드명에 해당하는 값이 있는 경우 해당 값을 반환하며, 없는 경우 NULL을 반환한다. ConcurrentHashMap의 putIfAbsent와는 다르게 동시성을 보장하지 않는다. |
getFieldPropertyMap |
맵 데이터 오브젝트에 설정된 필드와 정보를 FieldProperty 객체로 변환하여 반환한다. FieldProperty에는 logicalName과 physicalName, Class 정보가 담겨 있으며, logicalName과 physicalName은 맵 데이터 오브젝트의 get API를 통해 입력한 fieldName이다. |
4. DB 데이터 오브젝트 팩토리
본 절에서는 DBIO 작업을 위한 DB 데이터 오브젝트 팩토리에 대한 개념과 개발 방법에 대해 설명한다.
4.1. 구조
DB 데이터 오브젝트 팩토리(DBDataObjectFactory)는 DBIO 작업을 수행하기 위한 모듈이다. 하나의 DB 데이터 오브젝트 팩토리에는 개발자가 지정한 C/R/U/D 쿼리가 매핑되며, 개발자는 DB 데이터 오브젝트 팩토리를 사용하는 경우 수행하려는 쿼리를 선택해야 한다. 그외에도 DB 데이터 오브젝트 팩토리는 원할한 DBIO 작업을 위해 페이징 기능과 beforeImageLog 기능을 제공한다.
DB 데이터 오브젝트 팩토리는 4가지 종류의 쿼리와 쿼리 조건 파라미터를 멤버변수로 구성한다.
DB 데이터 오브젝트 팩토리 개발 방법은 쿼리를 선택한 후 파라미터 입력하는 과정으로 진행된다.
-
CASE1
팩토리에 자신이 사용할 쿼리를 지정하고 쿼리 조건을 바꿔가면서 사용하는 유형이다 .
-
CASE2
조건이 일정한 쿼리를 지정하여 사용하는 유형이다.
-
CASE3
로직에서 사용자로부터 직접 쿼리를 입력받아 수행하는 유형이다.
4.1.1. Condition
Condition은 개발자가 사용할 Separated Query의 조건문이다.
DB 데이터 오브젝트 팩토리에 CONDITION enum으로 구성되며, DB 데이터 오브젝트 팩토리 개발 당시 개발자가 지정한 SQL ALIAS로 구분된다. 조건 선택은 DB 데이터 오브젝트 팩토리의 setCondition API을 이용하며, 반드시 Separated Query가 선택되어 있어야 한다. Separated Query와 Condition은 서로 종속관계는 아니며, 한 쿼리에 대해서 다양한 조건을 연결하기 위해 사용된다.
-
예제 1)
SeparatedQueryFactory factory = new SeparatedQueryFactory("tibero"); //사용할 쿼리 선택 factory.setSeparatedQuery(SEPARATEDQUERY.SELECT1); //쿼리에 사용할 조건절 선택 factory.setCondition(CONDITION.C1); //CONDITION.C1 : ENAME = :ename AND SAL > :sal factory.setEname("John"); factory.setSal(100); //실제 수행되는 쿼리 SELECT ~ ... WHERE ENAME = 'John' AND SAL > 100
4.1.2. Separated Query
Separated Query는 개발자가 사용할 SQL 중 쿼리 조건문을 제외한 나머지 부분이다.
예를 들어 "SELECT * FROM EMP WHERE EMPNO = ?"라는 SQL을 사용하려면, Separated Query는 "SELECT * FROM EMP"까지만 구성한다.
Separated Query는 단독으로 사용될 수 없으며 반드시 Condtion과 조합하여 사용해야 한다. SeparatedQuery는 DB 데이터 오브젝트 팩토리에 'SEPARATEDQUERY’라는 enum으로 구성되어 있으며, DB 데이터 오브젝트 팩토리 개발 당시 개발자가 지정한 SQL ALIAS로 구분된다. 쿼리 선택은 DB 데이터 오브젝트 팩토리의 setSeparatedQuery API를 이용하며, 반드시 setCondition API를 통해 쿼리 조건문을 선택해줘야 정상적인 동작을 한다.
다음은 Separated Query와 Condition 조합을 이용하는 예제이다. 기본적인 사용법은 Full Query와 같다.
SeparatedQueryFactory factory = new SeparatedQueryFactory("tibero"); //사용할 쿼리 선택 factory.setSeparatedQuery(SEPARATEDQUERY.SELECT1); //쿼리에 사용할 조건절 선택 factory.setCondition(CONDITION.EMPNO); factory.setEmpno(1); SampleDataObject output = factory.get(); System.out.println(output.toString());
4.1.3. Full Query
Full Query는 개발자가 사용할 SQL 문을 뜻한다. DBIO를 수행하기 위한 쿼리 문자열이다.
'FULLQUERY’라는 enum으로 구성되어 있으며, DB 데이터 오브젝트 팩토리를 개발할 때 개발자가 지정한 SQL ALIAS로 구분된다. 쿼리 선택은 DB 데이터 오브젝트 팩토리의 setFullQuery API를 이용하며, 쿼리 선택 방식은 FULLQUERY.ALIAS로 선택할 수 있다.
다음은 Full Query의 사용법에 대한 설명이다.
-
단건조회 예제
//* 사용한 쿼리 : SELECT EMPNA.EMPNO, ENAME, JOB, SAL FROM EMP WHERE EMPNO = :empno //사용하려는 데이터소스명을 입력하여 DBDOF 객체 생성 FullQueryFactory factory = new FullQueryFactory("tibero"); //수행하려는 쿼리 선택 factory.setFullQuery(FULLQUERY.SELECT1); //파라미터 값 입력. 본로직에서는 쿼리의 조건을 입력하므로, //DBDOF의 파라미터에 해당하는 setter를 호출했다. factory.setEmpno(1); //단건조회용 API인 get 메소드를 호출하여 조회 결과를 Target DO로 반환받는다. SampleDataObject output = factory.get(); System.out.println(output.toString());
-
다건조회 예제
//* 사용한 쿼리 : SELECT EMPNA.EMPNO, ENAME, JOB, SAL FROM EMP WHERE ENAME = :ename
-
getForwardList
FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.SELECT1); factory.setEname("Michael"); //getForwardList API를 이용하여 다건조회 수행. //ForwardList는 iterator 조회와 get API만을 지원한다. //index 조정을 불가하며, iterator나 get을 통해 지나간 커서 위치는 재조회할 수 없다. for(SampleDataObject dataobject : factory.getForwardList()) { System.out.println(dataobject.toString()); }
-
getScrollableList
FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.SELECT1); factory.setEname("Michael"); //getScrollableList 메소드를 호출하여, 다건 조회 결과를 list로 반환받는다. ScrollableList<SampleDataObject> list = factory.getScrollableList(); //반환받은 list에 index 값을 입력하여 해당 커서 위치에 존재하는 조회 결과를 반환받을 수 있다. System.out.println(list.get(1)); System.out.println(list.get(2)); System.out.println(list.get(3));
-
getDataObjectList
FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.SELECT1); factory.setEname("Michael"); //java.util.ArrayList에 조회결과를 담아서 반환한다. ArrayList<SampleDataObject> list = factory.getDataObjectList(); System.out.println(list.get(0)); System.out.println(list.get(1)); System.out.println(list.get(2));
-
-
데이터 삽입 예제
//* 사용한 쿼리 : INSERT INTO EMPNA(EMPNO, ENAME, JOB, SAL) VALUES(:empno,:ename,:job,:sal) FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.INSERT1); SampleDataObject input = new SampleDataObject(); //Target DO를 생성하고 삽입할 데이터들을 입력한다. input.setEmpno(5); input.setEname("jung"); input.setJob("was3"); input.setSal((long)100); //add API를 호출하여 insert 쿼리를 수행한다. //add 메소드의 파라미터는 Target DO이며 boolean 값을 통해 addBatch 수행 여부를 지정한다. //true일 경우 addBatch를 수행하지 않는다. //add API의 리턴값은 변경된 데이터 수이다. System.out.println(factory.add(input, true));
-
데이터 수정 예제
//* 사용한 쿼리 : UPDATE EMPNA SET ENAME = :ename, JOB = :job, SAL = :sal WHERE EMPNO = :empno FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.UPDATE1); //UPDATE 쿼리의 조건 값을 입력한다. //모든 쿼리의 조건 값은 DBDOF에 설정한다. factory.setEmpno(1); //수정할 데이터값을 입력한다. //수정할 데이터값은 Target DO로 입력한다. SampleDataObject input = new SampleDataObject(); input.setEname("Michael"); input.setJob("was3"); input.setSal((long)100); System.out.println(factory.update(input, true));
-
데이터 삭제 예제
데이터 삭제의 경우 DELETE 쿼리에 테이블명과 조건절만 존재한다. 원칙상 쿼리의 조건 값은 DB 데이터 오브젝트 팩토리를 통해 입력받도록 되어 있지만, DELETE 쿼리에 한하여 Target DO에 조건 값을 입력할 수 있는 경우 Target DO로도 DELETE 쿼리 조건을 입력한다.
-
데이터 오브젝트를 통한 쿼리 조건 입력 예제
//* 사용한 쿼리 : DELETE FROM EMPNA WHERE EMPNO = :empno FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.DELETE1); //Target DO를 생성하고 삭제할 조건값을 입력한다. //이는 DBDOF를 통해 SELECT하거나 INPUT으로 들어온 //DO에서 추가적으로 값을 추출하는 과정을 거치지 않게 하기위한 방법이다. SampleDataObject input = new SampleDataObject(); input.setEmpno(1); System.out.println(factory.remove(input, true));
-
DBDOF에 직접 쿼리 조건 입력 예제
FullQueryFactory factory = new FullQueryFactory("tibero"); factory.setFullQuery(FULLQUERY.DELETE1); //쿼리 조건에 해당하는 파라미터 값 입력 factory.setEmpno(2); System.out.println(factory.remove(true));
-
4.1.4. User Query
User Query는 DB 데이터 오브젝트 팩토리 개발 당시 Full Query나 Separated Query로 지정하지 않은 쿼리를 사용하기 위한 방법이다.
SO나 BO의 로직에서 개발자로부터 직접 쿼리와 쿼리 파라미터를 입력받는다. setUserQuery API를 이용해서 로직에서 사용할 쿼리 문자열을 입력하고, setBindingParameter API를 이용해서 쿼리의 파라미터값을 입력한다.
User Query는 DB 데이터 오브젝트 팩토리를 통해 반복적으로 사용할 쿼리가 아닌 특정 로직에서만 일회성으로 사용되는 쿼리를 입력받기 위한 방법이므로 범용적으로 사용되는 쿼리의 경우 Full Query 또는 Separated Query를 이용해야 한다.
다음은 User Query를 사용하는 예제이다.
FullQueryFactory factory = new FullQueryFactory("tibero"); StringBuilder query = new StringBuilder(); query.append("SELECT * \n"); query.append("FROM EMPNA \n"); query.append("WHERE \n"); query.append("EMPNO = :empno"); factory.setUserQuery(query.toString()); factory.setBindParameter("empno", new Integer(1)); SampleDataObject output = factory.get(); System.out.println(output.toString());
4.1.5. Dynamic Query
Dynamic Query는 런타임에 동적으로 SQL 문을 조립하는 것이 가능하다. 컴파일 단계에서 SQL 문의 전체 텍스트를 알 수 없을 때 Dynamic Query를 활용하여 범용적이고 유연한 응용 프로그램을 작성할 수 있다.
DB 데이터 오브젝트 팩토리는 Mybatis의 Dynamic SQL 문법의 if, choose, when, otherwise, trim, where, set, foreach 엘리먼트를 지원한다.
-
if
if 엘리먼트는 테스트 결과에 따라 선택적으로 구문을 쿼리에 추가하며, where절의 일부로 포함될 수 있다.
SELECT * FROM EMP WHERE DEPTNO = 10 <if test="ename != null"> AND ENAME like '#{ename}%' </if>
ename의 값이 없다면 DEPTNO = 10인 모든 employee가 리턴된다. 하지만 ename 값이 있다면 그 값으로 이름이 시작하는 employee를 찾는다.
-
choose, when, otherwise
choose, when, otherwise 엘리먼트는 Java의 switch 구문과 유사하다.
SELECT * FROM EMP WHERE DEPTNO = 10 <choose> <when test="ename != null"> AND ENAME like #{ename} </when> <when test="job != null"> AND JOB like #{job} </when> <otherwise> AND sal = 100 </otherwise> </choose>
ename에 값이 있다면 ename 구문이 선택되고, job에 값이 있다면 job 구문이 선택된다. 두 값 모두 없다면 sal 구문이 선택된다.
-
where, trim, set
다음과 같이 if 엘리먼트를 사용하면 문제가 발생한다.
SELECT * FROM EMP WHERE <if test="deptno != null"> DEPTNO = #{deptno} </if> <if test="ename != null"> AND ENAME like #{ename} </if>
deptno에 값이 없고 ename에도 값이 없다면 다음과 같이 SQL 문법에 맞지않는 쿼리가 만들어진다.
SELECT * FROM EMP WHERE
ename에 값만 있다면 다음과 같은 쿼리가 만들어지고 역시 문법에 맞지 않는다.
SELECT * FROM EMP WHERE AND ENAME like 'kim'
where 엘리먼트는 이런 문제를 해결한다.
SELECT * FROM EMP <where> <if test="deptno != null"> DEPTNO = #{deptno} </if> <if test="ename != null"> AND ENAME like #{ename} </if> </where>
where 엘리먼트는 쿼리에 동적으로 "WHERE" 키워드를 추가하며, 엘리먼트가 반환하는 구문이 "AND"나 "OR" 키워드로 시작하면 그 키워드를 지운다.
where 엘리먼트는 trim 엘리먼트를 사용하여 다음과 같이 대체할 수 있다.
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
set 엘리먼트는 다음과 같이 사용하며, 동적으로 "SET" 키워드를 쿼리에 추가하고, 필요없는 콤마를 제거한다.
UPDATE EMP <set> <if test="ename != null">ENAME=#{ename},</if> <if test="deptno != null">EMPNO=#{deptno},</if> <if test="job != null">JOB=#{job}</if> </set> where EMPNO=1234
set 엘리먼트 역시 trim 엘리먼트를 사용하여 대체할 수 있다.
<trim prefix="SET" suffixOverrides=","> ... </trim>
이와 같은 방식으로 trim 엘리먼트는 사용자 정의에 따라 유연하게 활용할 수 있다.
-
foreach
foreach 엘리먼트는 collection에 대해 반복 처리를 해서 쿼리를 작성할 수 있게 한다.
SELECT * FROM EMP WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach>
foreach 엘리먼트는 엘리먼트 내부에서 사용할 수 있는 item, index 변수를 선언한다. 또한 열고 닫는 문자열을 명시할 수 있고, 반복간에 둘 수 있는 구분자를 추가할 수 있다.
DB 데이터 오브젝트 팩토리에서 Dynamic Query는 'DynamicQueryImple' enum으로 구성되어 있으며, DB 데이터 오브젝트 팩토리를 개발할 때 개발자가 지정한 SQL ALIAS로 구분된다. 쿼리 선택은 DB 데이터 오브젝트 팩토리의 setDynamicQuery API를 이용하며, 쿼리 선택 방식은 DynamicQueryImple.ALIAS로 선택할 수 있다.
다음은 Dynamic Query를 사용하는 예시이다.
-
다건 조회 예제
//* 사용한 쿼리 : SELECT * FROM EMP <where> <if test="deptno != null"> DEPTNO = #{deptno} </if> <if test="ename != null"> AND ENAME LIKE #{ename} </if> </where> //사용하려는 데이터소스명을 입력하여 DBDOF 객체 생성 DynamicQueryFactory factory = new DynamicQueryFactory("tibero"); //수행하려는 쿼리 선택 factory.setDynamicQuery(DynamicQueryFactory.DynamicQueryImple.SELECT1); //파라미터 값 입력 factory.setEname("kim"); //단건조회용 API인 get 메소드를 호출하여 조회 결과를 Target DO로 반환받는다. EmpDO output = factory.get();
4.2. 개발 방법
본 절에서는 DB 데이터 오브젝트 팩토리를 개발하는 과정과 개발된 DB 데이터 오브젝트 팩토리를 이용하여 DBIO를 수행로직을 개발하는 방법에 대해서 설명한다.
4.2.1. 선행 개발 과정
DB 데이터 오브젝트 팩토리를 개발하기 위해서는 반드시 다음의 과정이 선행되어야 한다.
-
데이터소스 목록 정의
dbio_config.xml에 DB 데이터 오브젝트 팩토리에서 사용할 데이터소스 목록을 정의해야 한다.
-
데이터 오브젝트 생성
데이터 오브젝트 팩토리를 개발하기 위해서는 반드시 기반이 될 데이터 오브젝트가 존재해야 한다.
데이터 오브젝트 팩토리를 개발하기 위해서는 데이터 오브젝트가 선행 개발되어야 한다. 데이터 오브젝트는 흔히 쓰이는 개념인 DataTransferObject의 개념에서 확장되어 ORM의 Entity 개념을 포함하고 있다. ProObject에서는 데이터 오브젝트가 서비스 간의 input, output을 담당하며 DBIO와 FILE IO의 단위이다. DBIO로 사용하려는 데이터 오브젝트를 개발할 때는 SQL을 수행하려는 대상 테이블들의 view로 생각한다. 기본적인 데이터 오브젝트에 대한 개발 방법은 데이터 오브젝트를 참고한다.
다음은 DB 데이터 오브젝트 팩토리를 이용해서 개발하는 경우 유의해야 할 사항에 대한 설명이다.
-
Non Persistence DataObject
데이터 오브젝트와 DB 스키마의 연관성이 없는 형태를 뜻한다. DB 스키마 정보가 포함되지 않은 메타를 사용하여 개발된 데이터 오브젝트이다. 이런 형태의 데이터 오브젝트를 DB 데이터 오브젝트 팩토리에서 사용하기 위해서는 데이터 오브젝트의 멤버변수명(META의 Physical Name)과 쿼리에서 사용된 column 이름 또는 alias 이름이 일치해야 한다.
-
Persistence DataObject
데이터 오브젝트와 DB 스키마가 coupling된 형태를 뜻한다. DB 스키마 정보가 포함된 메타를 사용하여 개발된 데이터 오브젝트이다. 메타의 physical name과 관계없이, 메타에 지정된 schema, table, column이 일치하는 값만 가져온다.
Column과 데이터 오브젝트의 매핑 우선순위는 다음과 같다.
-
데이터 오브젝트의 멤버변수명(메타의 Physical Name)과 alias 이름이 일치하는 경우
-
데이터 오브젝트의 멤버변수에 해당하는 컬럼명(메타의 Column Name)과 DB 컬럼 이름이 일치하는 경우
-
데이터 오브젝트의 멤버변수명(메타의 Physical Name)과 쿼리에서 사용된 컬럼 이름이 일치하는 경우
-
Target DO는 DB 데이터 오브젝트 팩토리의 select 결과물을 받아오기 위한 혹은 insert, update할 값을 입력하기 위한 단위이다. ProObject에서는 Target DO를 DBIO를 수행할 TABLE VIEW로 간주하며, Target DO를 생성할 때에도 Table 단위 혹은 View 단위로 구성하여 사용하길 권장한다.
Target DO는 DB 데이터 오브젝트 팩토리의 단위가 되기도 하지만 데이터 오브젝트의 특성을 그대로 갖고 있으므로, 서비스의 INPUT, OUTPUT으로 사용 가능하며 메시지 클래스를 생성할 수도 있다. Target DO를 선택할 때에 데이터 오브젝트의 멤버변수로 다른 데이터 오브젝트를 포함하는 경우는 허용하지 않으므로 주의한다.
-
-
데이터 오브젝트 선택
데이터 오브젝트 팩토리의 기반이 될 데이터 오브젝트를 선택한다. DB 데이터 오브젝트 팩토리는 선택된 데이터 오브젝트 형태로 쿼리 조회결과를 리턴하고, insert/update/delete 값을 입력받는다.
-
SQL 입력
DB 데이터 오브젝트 팩토리에서 사용할 쿼리를 입력한다. 쿼리는 여러 개를 입력가능하며, SO/BO에서 데이터 오브젝트 팩토리를 사용하는 경우 동작할 쿼리를 선택할 수 있다.
DB 데이터 오브젝트 팩토리는 사용할 SQL을 미리 입력하고, SO나 BO에서 해당 SQL을 호출한다. DB 데이터 오브젝트 팩토리에 사용할 SQL의 개수는 제한이 없으나, 동일한 내용의 SQL을 중복해서 입력할 수 없다. 개발자는 C/R/U/D 타입별로 자신이 사용할 SQL을 DB 데이터 오브젝트 팩토리에 입력할 수 있으며, 반드시 SQL에 해당하는 SQL ALIAS를 입력해야 한다. SQL ALIAS는 DB 데이터 오브젝트 팩토리를 통해 개발자가 사용할 SQL을 선택할 때 SQL을 구분하는 단위가 되므로 반드시 사용자가 이해할 수 있는 의미를 담아 지정하도록 한다.
DB 데이터 오브젝트 팩토리를 개발하기 위해서는 데이터 오브젝트 팩토리의 기반이 되는 데이터 오브젝트를 선행 개발해야 한다. DB 데이터 오브젝트 팩토리는 SELECT SQL의 결과를 데이터 오브젝트로 제공하며, insert/update SQL의 VALUE를 데이터 오브젝트로 입력 받는다.
4.2.2. 수행로직 개발
DB 데이터 오브젝트 팩토리를 이용한 개발은 다음의 과정으로 진행된다.
-
데이터소스 설정 및 객체 생성
DB 데이터 오브젝트 팩토리는 ProObject에서 제공하는 기본 DI(Dependency Injection)의 대상이 아니다. 그러므로 개발자가 직접 DI 기능을 추가해주지 않는한, DB 데이터 오브젝트 팩토리의 객체를 생성해야 한다. DB 데이터 오브젝트 팩토리는 Constructor에 데이터소스명을 직접 입력받도록 되어 있으며, 데이터소스명이 입력되지 않는 경우 ProObject.xml에 설정된 기본 데이터소스를 사용하게 된다. 사용하려는 데이터소스는 반드시 dbio_config.xml에 설정된 PairDataSource의 alias명과 일치해야 한다.
-
쿼리 선택
사용할 데이터소스명을 지정하여 DB 데이터 오브젝트 팩토리의 객체를 생성한 후 개발에 필요한 쿼리를 선택해야 한다.
사용할 쿼리 종류에 따라서 Full Query의 경우 setFullQuery API를 호출하고 Separated Query의 경우 setSeparatedQuery와 setCondition을 API를 호출하여 사용할 쿼리를 선택한다. 반복해서 사용할 쿼리가 아닌 일회성 쿼리의 경우 setUserQuery API를 통해 쿼리를 입력할 수 있으며, 파라미터는 setBindingParameter API를 호출해서 설정할 수 있다.
선택한 쿼리는 쿼리 수행 API들(get, getForwardList, getScrollableList, getDataObjectList, add, update, delete)이 호출된 후에는 초기화되므로 쿼리를 반복 수행할 때는 반드시 쿼리 수행 API 호출 전에 쿼리 선택 API를 호출한다.
-
파라미터 값 입력
기존 Java JDBC에서는 쿼리 안에서 파라미터 값들을 '?'로 표시했으며, 파라미터 값은 setObject(int index)와 같이 개발자가 파라미터 위치를 지정해줘야 한다.
이러한 불편함을 해소하기 위해 DB 데이터 오브젝트 팩토리에 쿼리를 작성할 때 파라미터 부분을 ':파라미터명'으로 지정한다. ':파라미터명'으로 설정된 쿼리의 경우 DB 데이터 오브젝트 팩토리에서 실제 쿼리를 수행할 때 '?'로 치환하고 인덱스 번호를 맞춰서 JDBC Operation을 수행한다.
다만 Dynamic Query 사용시, 파라미터를 표현하는 방식이 다르다. 쿼리 조건에 위치한 파라미터의 경우 '#{파라미터명}'으로 지정하며, 데이터 삽입/수정에 대한 파라미터의 경우 Target DO를 통해 값을 입력받는다는 의미를 담아 '#{do.파라미터명}'로 지정한다.
쿼리에 설정된 파라미터의 위치에 따라 DB 데이터 오브젝트 팩토리에 파라미터 값을 입력하는 방식은 두 가지로 나뉜다.
-
쿼리 조건(쿼리 내 WHERE 절에 해당하는 파라미터)에 위치한 파라미터 값을 입력하는 방법
쿼리 조건에 해당하는 파라미터들은 DB 데이터 오브젝트 팩토리에 멤버변수로 선언되며, 파라미터 값도 DB 데이터 오브젝트 팩토리의 파라미터에 해당하는 Setter 메소드를 호출하여 입력한다.
-
데이터 삽입/수정에 대한 파라미터 값을 입력하는 방법
데이터 삽입/수정에 대한 파라미터란 INSERT 쿼리의 VALUES() 절에 포함되는 파라미터들이나 UPDATE 쿼리의 SET() 절에 포함되는 파라미터들을 뜻한다. 이러한 파라미터들은 Target DO에 값을 입력해야 한다. 즉, 파라미터 명과 Target DO의 멤버변수명이 일치해야 한다.
쿼리 조건에 해당하는 파라미터와 데이터 삽입/수정에 해당하는 파라미터 값 입력방식이 다른 이유에 대해서 설명한다. 우선 쿼리 조건에 해당하는 파라미터의 경우 조건에 따라 다양한 이름으로 설정할 수 있다. 예를 들어 나이의 범위를 지정하는 조건의 경우 AGE라는 컬럼에 대해서 다음과 같이 쿼리를 구성할 수 있다.
AGE > :mimAge AND AGE < :maxAge
maxAge나 minAge와 같은 변수까지 모두 데이터 오브젝트에 선언하는 것은 불필요한 멤버변수를 늘리는 행위이므로 데이터 오브젝트가 아닌 DB 데이터 오브젝트 팩토리를 통해 파라미터 값을 입력받을 수 있다. 반면 데이터 삽입/수정 쿼리의 경우 입력받는 데이터 파라미터가 테이블의 컬럼과 정확하게 1:1로 일치한다. 예를 들어 "INSERT INTO EMP(EMPNO, ENAME, AGE) VALUES(~) "와 같은 쿼리에서 VALUES에 해당하는 파라미터들은 삽입하려는 테이블 컬럼에 1:1로 매핑하도록 제한된다.
-
-
쿼리 수행 API 호출
실행할 쿼리를 선택하고 파라미터까지 입력한 다음에는 DBIO 작업을 수행할 API를 호출한다. DBIO용 API는 C/R/U/D별로 나누어져 있으며, SELECT는 다시 단건 조회용 다건 조회용으로 나뉜다. API에 대한 설명은 DB 데이터 오브젝트 팩토리 API를 참고한다.
DBIO API를 호출하면 DB 데이터 오브젝트 팩토리에 설정했던 쿼리와 파라미터 정보가 초기화되므로 똑같은 쿼리를 반복 수행한다고 해도 위에서 설명한 '2.쿼리 선택’과 '3.파라미터 입력’까지의 과정을 반복해야 한다.
-
DB 데이터 오브젝트 팩토리 사용종료 명령
ProObject에서 DB 데이터 오브젝트 팩토리를 사용하는 경우 DB 리소스에 대한 관리를 자동으로 처리한다. 그러나 반복문을 통한 DB 데이터 오브젝트 팩토리 생성 등 단시간에 DB 리소스를 지나치게 사용하는 경우 또는 사용자가 임의로 리소스를 해제하는 경우를 위해 데이터 오브젝트 팩토리는 cleanUp() API를 제공하고 있다. 데이터 오브젝트 팩토리의 cleanUp() API가 호출되면, 데이터 오브젝트 팩토리는 모든 행위를 중단하고 자신이 할당받은 리소스들을 해제한다.
4.3. DB 데이터 오브젝트 팩토리 API
다음은 DB 데이터 오브젝트 팩토리가 제공하는 API 목록이다.
-
C/R/U/D Operataion 수행 전 쿼리 선택
-
SELECT 수행
-
단건 조회 : get
-
다건 조회 : getForwardList, getScrollableList, getDataObjectList
-
데이터 갯수 조회 : getResultCount
-
-
INSERT, UPDATE, DELETE 수행
-
모두 파라미터로 데이터 오브젝트를 입력받으며 boolean 값으로 addBatch 여부를 설정할 수 있다.
-
페이징 기능관련
-
쿼리 타임아웃
-
데이터 결과 관련
-
데이터 페치 관련
-
초기화 관련
다음은 API에서 사용하는 타입에 대한 설명이다.
구분 | 설명 |
---|---|
ForwardList |
ForwardList는 iterator와 get 메소드만 사용 가능하며, 한 번 조회한 값은 재조회가 불가능하다. ForwardList는 DB 데이터 오브젝트 팩토리의 다건조회 결과물로써, DBIO 작업의 결과를 데이터 오브젝트 형태로 가지고 있는 리스트이다. java.util.ArrayList와 달리 모든 결과물을 가지고 있는 것이 아니라, ForwardList의 get API가 호출되는 시점에서 DBIO 결과물을 데이터 오브젝트로 변환해서 하나씩 반환한다. 또한 한번 조회된 인덱스의 결과물은 두 번 조회할 수 없는 forward-only이다. ForwardList는 개발자가 임의로 생성하지 않아야 하는 객체이며, DB 데이터 오브젝트 팩토리의 다건조회 결과물로써 받아서 사용할 수 있다. ForwardList를 Iterator 혹은 for-each로 사용한 것이 아닌 객체를 생성하여 사용했다면 반드시 데이터 오브젝트 팩토리의 cleanUp(ForwardList list) API를 호출하여 ForwardList가 사용한 DB 리소스를 해제한다. |
ScrollableList |
ScrollableList는 iterator를 통한 순차 조회와 get(int index)를 통한 cursor 조회가 가능하다. ScrollableList는 DB 데이터 오브젝트 팩토리의 다건조회 결과물로써, DBIO 작업의 결과를 데이터 오브젝트 형태로 가지고 있는 리스트이다. 사용법은 ForwardList와 동일하지만, 사용자가 조회하고 싶은 인덱스 위치를 지정할 수 있다는 점이 다르다. ForwardList와 다르게 get API에 파라미터로 인덱스를 지정할 수 있으며, 해당 위치의 결과 값을 데이터 오브젝트로 반환받을 수 있다. ScrollableList의 사용이 종료되었다면 반드시 데이터 오브젝트 팩토리의 cleanUp(ScrollableList list) API를 호출하여 ScrollableList가 사용한 DB 리소스를 해제한다. |
DataObjectList |
DataObjectList는 DB 데이터 오브젝트 팩토리의 다건조회 결과물을 ArrayList에 담아서 준다. 즉, 모든 조회 결과가 ArrayList에 담겨서 제공되므로 조회 결과가 많은 경우 사용에 주의한다. |
4.3.1. add
데이터 삽입을 수행할 때 호출하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
테이블에 삽입하려는 데이터를 데이터 오브젝트로 입력받아, INSERT 쿼리를 수행한다. 파라미터 값에 따라 Java JDBC PreparedStatement의 addBatch를 수행한다.
-
immediate = true : PreparedStatement의 executeUpdate를 수행한다. API 호출 즉시 쿼리를 수행한다.
-
immeidate = false : PreparedStatement의 addBatch를 수행한다. 사용자가 입력한 쿼리를 즉시 수행하지 않고 DB 데이터 오브젝트 팩토리의 executeAll이 호출되었을 경우 쿼리를 수행한다.
-
add(DataObject insert, boolean immediate) 메소드의 immediate 변수 값이 false인 경우와 동일한 기능을 수행한다.
int add(DataObject insert, boolean immediate) void add(DataObject insert)
-
입력받은 리스트의 데이터 오브젝트들에 대해서 add(DataObject insert) 동작을 수행한 후 DB에 반영한다.
int add(List <DataObject> insertList)
-
auto increased 속성을 지닌 column의 값을 구하기 위한 API이다. 입력값으로 넘겨준 데이터 오브젝트의 필드에 auto increased column의 데이터를 담아준다.
int add(DataObject insert, String... autoIncreasedFields)
-
-
사용법 2)
userQuery를 사용하는 경우 데이터를 삽입하기 위한 API로 Java JDBC의 addBatch를 수행하지 않고, 쿼리 결과를 DB에 반영한다.
int add()
4.3.2. clearBatch
add, update, remove API들을 통해 addBatch된 내역들에 대한 DB 반영을 취소한다. clearBatch는 사용자가 명시적으로 호출할 수도 있지만, 서비스가 실패한 경우 엔진 내부에서 호출한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void clearBatch()
4.3.3. cleanUp
데이터 오브젝트 팩토리의 사용을 종료하고 데이터 오브젝트 팩토리가 사용한 모든 리소스를 반환한다. 일반적으로 서비스가 종료될 때 엔진에서 호출하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
DB 데이터 오브젝트 팩토리를 통해 생성한 ForwardList를 메모리에서 해제한다. ForwardList를 통해 리스트의 마지막까지 조회한 경우 엔진에서 호출한다. 인자로 받은 ForwardList를 생성하는데 사용했던 DB 자원을 해제한다.
void cleanUp() void cleanUp(ForwardList<T> forwardlist)
-
사용법 2)
DB 데이터 오브젝트 팩토리를 통해 생성한 ScrollableList를 메모리에서 해제한다. ScrollableList의 사용을 종료하고 난 후에는 반드시 호출해야 한다. 인자로 받은 ScrollableList를 생성하는데 사용했던 DB 자원을 해제한다.
void cleanUp(ScrollableList<T> scrollablelist)
4.3.4. executeAll
add, update, remove API들을 통해 addBatch된 내역들을 DB에 반영하는 기능을 수행한다.
executeAll은 사용자가 명시적으로 호출할 수도 있지만 다음의 경우 엔진 내부에서 호출하기도 한다.
-
서비스가 성공적으로 종료된 경우 트랜잭션 커밋을 수행하기 전에 엔진에서 호출한다.
-
get, getForwardList, getScrollableList, getDataObjectList를 통해서 데이터를 조회하기 전에 호출한다.
-
이전에 수행한 쿼리와 현재 수행하려는 쿼리가 다른 경우 호출한다. 메소드의 반환값으로 addBatch되었던 내역의 갯수를 사용자에게 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
int executeAll()
4.3.5. get
다건 조회를 수행할 때 호출하는 API이다. 쿼리 수행 결과를 ArrayList에 담아서 결과를 데이터 오브젝트 하나에 매핑하여 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
DataObject get(void)
4.3.6. getDataObjectList
다건 조회를 수행할 때 호출하는 API이다. 쿼리 수행 결과를 ArrayList에 담아서 반환한다. 모든 조회 결과값이 ArrayList에 담겨있기 때문에 결과 개수에 따라 memory overflow를 고려해야 한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
ArrayList getDataObjectList(void)
4.3.7. getForwardList
다건 조회를 수행할 때 호출하는 API이다. 쿼리 수행 결과를 ForwardList에 매핑하여 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
ForwardList getForwardList(void)
4.3.8. getResultCount
데이터 조회 결과수를 확인하는 API이다.
get(), getForwardList(), getScrollableList(), getDataObjectList()처럼 조회 결과를 받는 것이 아니라 조회 결과의 개수를 long 값으로 반환받기 위한 API다. API 호출 전에 데이터 조회를 위해 쿼리 선택 및 조건값을 설정하고, getResultCount()를 호출한다. 사용자가 선택한 쿼리에 "SELECT COUNT(*)" 쿼리를 붙여서 사용자가 선택한 쿼리의 결과 개수를 구한다. 실제로 조회용 쿼리가 실행되는 것을 참고한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
long getResultCount()
4.3.9. getScrollableList
다건 조회를 수행할때 호출하는 API이다. 쿼리 수행 결과를 ScrollableList에 매핑하여 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
ScrollableList getScrollableList(void)
4.3.11. setCondition
DB 데이터 오브젝트 팩토리의 C/R/U/D Operataion을 수행하기 전 선택한 SeparatedQuery에 대한 쿼리 조건을 설정한다. DB 데이터 오브젝트 팩토리를 개발하는 경우 지정한 FullQuery의 enum을 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
setCondition(FULLQUERY Enum)
4.3.12. setFetchSize
데이터를 조회하는 경우 조회할 데이터의 페치 크기를 설정한다. API의 파라미터값을 이용하여 Java JDBC의 PreparedStatement의 setFetchSize를 호출한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void setFetchSize(int fetchSize)
4.3.13. setFullQuery
DB 데이터 오브젝트 팩토리의 C/R/U/D Operataion을 수행하기 전 쿼리를 선택하기 위한 메소드이다.
DB 데이터 오브젝트 팩토리를 개발하는 경우 지정한 FullQuery의 enum을 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
setFullQuery(FULLQUERY Enum)
4.3.14. setDynamicQuery
DB 데이터 오브젝트 팩토리의 C/R/U/D Operataion을 수행하기 전 쿼리를 선택하기 위한 메소드이다.
DB 데이터 오브젝트 팩토리를 개발하는 경우 지정한 DynamicQueryImple의 enum을 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
setDynamicQuery(DynamicDOF.DynamicQueryImple Enum)
4.3.15. setPageNumber
페이징 기능을 이용하여 조회할 페이지 번호를 선택한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void setPageNumber(int pageNumber) void setPageNumber(int pageNumber, String sortField, String sortType)
4.3.16. setPageSize
페이징 기능을 사용하여 데이터를 조회했을 때 페이지의 크기를 설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void setPageSize(int size)
4.3.17. setPageQuery
ProObject의 페이징 기능은 Oracle, Tibero 기준으로 동작한다. Oracle, Tibero 이외의 DB에서 페이징을 원하는 경우 이 API를 이용한다. 예를 들어 DB2의 페이징 기능을 이용하려면 API의 파라미터로 "LIMIT"을 설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void setPageQuery(String pageQuery)
4.3.18. setSeparatedQuery
DB 데이터 오브젝트 팩토리의 C/R/U/D Operataion을 수행하기 전 쿼리를 선택하기 위한 메소드이다.
DB 데이터 오브젝트 팩토리를 개발하는 경우 지정한 SeparatedQuery의 enum을 입력한다. SeparatedQuery를 사용할 때 반드시 setCondition API를 통해 쿼리에 사용할 조건도 입력해야 한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
setSeparatedQuery(SEPARATEDQUERY Enum)
4.3.19. setTimeout
쿼리 수행시간에 제한을 설정할 수 있는 API이다.
API의 파라미터 값을 이용하여 쿼리 수행 전 Java JDBC의 PreparedStatement에 setQueryTimeout을 호출한다.
설정된 값과 WAS의 설정값, 서비스 타임아웃까지 남은 시간중 비교하여 제일 작은 값을 쿼리 타임아웃 값으로 사용한다. 단, 입력받은 값이 '0’인 경우 사용자가 명시적으로 쿼리 타임아웃 시간을 무제한으로 지정한것이기 때문에, 쿼리 타임아웃 시간을 '0’으로 설정한다. 해당 API나 설정을 통해 쿼리타임아웃 시간을 지정하지 않은 경우 WAS의 기본 설정값과 서비스 타임아웃 시간까지 남은 시간중 제일 작은 시간을 쿼리 타임아웃 시간으로 결정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void setTimeout(Integer timeout)
4.3.20. reloadDataObjectConfig
ProManager를 통해 설정했던 데이터 오브젝트 팩토리의 설정들을 재설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void reloadDataObjectConfig()
4.3.21. remove
데이터 삭제를 수행할 때 호출하는 API이다.
데이터 삭제는 삽입과 수정 API와 동일하게 삭제하려는 조건 값을 DB 데이터 오브젝트 팩토리에 바로 설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
파라미터 값에 따라 Java JDBC PreparedStatement의 addBatch를 수행한다.
int remove(boolean immediate)
파라미터 설명 boolean immediate
-
true : PreparedStatement의 executeUpdate를 수행한다. API 호출 즉시 쿼리를 수행한다.
-
false : PreparedStatement의 addBatch를 수행한다. 사용자가 입력한 쿼리를 즉시 수행하지 않고 DB 데이터 오브젝트 팩토리의 executeAll이 호출되었을 경우 쿼리를 수행한다.
-
-
사용법 2)
userQuery를 사용하는 경우 데이터를 삽입하기 위한 API로 Java JDBC의 addBatch를 수행하지 않고, 쿼리 결과를 DB에 반영한다.
int remove()
4.3.22. update
데이터 수정을 수행할 때 호출하는 API이다.
테이블에 수정하려는 데이터를 데이터 오브젝트로 입력받아 UPDATE 쿼리를 수행한다.
수정하려는 데이터의 조건 값으로 쿼리의 WHERE에 해당하는 파라미터는 DB 데이터 오브젝트 팩토리의 동일한 파라미터 Setter를 통해 값을 입력하고, 수정하려는 데이터는 데이터 오브젝트에 설정한 후 DB 데이터 오브젝트 팩토리의 update API의 파라미터로 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
파라미터 값에 따라 JDBC PreparedStatement의 addBatch를 수행한다.
-
update(DataObject update, boolean immediate) 메소드의 immediate 변수 값이 false인 경우와 동일한 기능을 수행한다.
int update(DataObject update, boolean immediate) void update(DataObject update)
파라미터 설명 boolean immediate
-
true : PreparedStatement의 executeUpdate를 수행한다. API 호출 즉시 쿼리를 수행한다.
-
false : PreparedStatement의 addBatch를 수행한다. 사용자가 입력한 쿼리를 즉시 수행하지 않고 DB 데이터 오브젝트 팩토리의 executeAll이 호출되었을 경우 쿼리를 수행한다.
-
-
입력값으로 넘겨준 데이터 오브젝트의 필드에 auto increased column의 데이터를 담아준다.
int update(DataObject update, String... autoIncreasedFields)
-
-
사용법 2)
userQuery를 사용하는 경우 데이터를 삽입하기 위한 API로 Java JDBC의 addBatch를 수행하지 않고, 쿼리 결과를 DB에 반영한다.
int update()
4.3.23. setEmptyResultCheck
SELECT 쿼리를 이용하여 데이터 조회시, 조회 여부를 확인하고, 조회값이 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
boolean 값을 파라미터로 입력받으며, 파라미터 값에 따라서 설정 적용여부가 결정된다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setEmptyResultCheck(boolean emptyResultCheck)
파라미터 설명 boolean immediate
-
true : SELECT 쿼리를 수행하는 경우 조회 여부를 확인하고, 조회값이 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
-
false : 조회값 존재 여부를 확인하지 않는다.
-
4.3.24. setEmptyResultCheckForUpdate
INSERT, UPDATE, DELETE 쿼리를 수행할 경우 쿼리가 적용된 ROW가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
addBatch로 수행되는 쿼리나 executeBatch가 수행되는 쿼리에 대해서는 설정을 적용하지 않는다.
boolean 값을 파라미터로 입력받으며, 파라미터 값에 따라서 설정 적용여부가 결정된다. 데이터 오브젝트 팩토리의 add, update, remove API 호출시 적용되는 옵션이며, add(input, false), update(input, false), remove(input, false) 혹은 add(input), update(input), remove(input)과 같이 JDBC의 addBatch 기능을 적용할때에는 옵션을 적용하지 않는다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setEmptyResultCheckForUpdate(boolean emptyResultCheckForUpdate)
파라미터 설명 boolean emptyResultCheckForUpdate
-
true : INSERT, UPDATE, DELETE 쿼리를 수행하는 경우 쿼리가 수행된 ROW 수를 확인하고, 적용된 ROW가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
-
false : 쿼리가 수행된 ROW 수를 확인하지 않는다.
-
4.3.25. setSingleResultCheck
데이터 오브젝트 팩토리의 get API를 이용해서 데이터 조회시, 조회 여부를 확인하고, 조회값 두개 이상 존재하는 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
boolean 값을 파라미터로 입력받으며, 파라미터 값에 따라서 설정 적용여부가 결정된다. 데이터 오브젝트 팩토리의 get API를 이용해서 SELECT 쿼리를 수행시키는 경우에만 적용되며, getForwardList, getScrollableList, getDataObjectList API를 사용할때는 적용되지 않는다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setSingleResultCheck(boolean singleResultCheck)
파라미터 설명 boolean singleResultCheck
-
true : SELECT 쿼리를 수행하는 경우 조회여부를 확인하고, 조회 결과가 두건 이상 존재하는 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
-
false : 조회 결과 조회된 데이터의 갯수를 확인하지 않는다.
-
4.3.26. setMaxRows
SELECT를 이용하여 데이터 조회시, 조회할수 있는 최대 ROW갯수를 제한한다.
파미터 값에 따라 com.tmax.proobject.dataobject.exception.MaxRowException을 발생시키기도 하며, JDBC 설정을 통해 지정된 ROW수만을 조회하게 할수 있다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
getForwardList, getScrollableList, getDataObjectList API 사용시 조회된 데이터의 갯수를 제한한다.
설정된 정수값을 넘어서는 데이터가 조회된 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
public void setMaxRows(int maxRows)
파라미터 설명 int maxRows
조회할 row의 상한선을 입력한다.
-
사용법 2)
getForwardList, getScrollableList, getDataObjectList API를 사용하는 경우 조회된 데이터의 갯수를 제한한다.
파라미터 값에 따라 설정된 정수값을 넘어서는 데이터가 조회된 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
public void setMaxRows(int maxRows, boolean throwException)
파라미터 설명 int maxRows
조회할 row의 상한선을 입력한다.
boolean throwException
-
true : maxRows 이상의 데이터가 조회된 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
-
false : java.sql.Statement의 setMaxRows api에 사용자가 설정한 maxRows 값을 설정한다.
-
4.4. BeforeImage 기능
데이터 오브젝트 팩토리의 BeforeImage 기능은 데이터 오브젝트 팩토리에 매핑한 C/U/D 쿼리를 수행하여 테이블에 변경이 일어나면 변경되기 전의 로우 정보(BeforeImage)와 변경된 로우 정보(AfterImage)를 별도의 테이블에 기록한다.
Insert 문을 수행하는 경우 추가된 로우 정보를 기록하고, Delete 문을 수행하는 경우 삭제된 로우 정보를, Update 문을 수행하는 경우 변경 전과 변경 후의 로우 정보를 모두 기록한다. 이렇게 기록된 정보는 추후 사용자가 특정 시점으로 테이블을 되돌리려고 할 경우 활용될 수 있다.
다음은 BeforeImage 기능을 개발하는 과정에 대한 설명이다.
-
BeforeImage 테이블 생성
BeforeImage 테이블은 데이터 오브젝트 팩토리에 매핑된 C/U/D 쿼리가 수행되는 테이블명에 "_BF_IMG"가 뒤에 붙은 이름을 가져야 한다. 예를 들어 EMP 테이블이 원장 테이블인 경우 BeforeImage 테이블명은 EMP_BF_IMG이다.
테이블의 컬럼들은 원장 테이블의 모든 컬럼을 필수적이며 다음과 같은 컬럼을 추가로 가진다.
컬럼명 & 데이터타입 데이터타입 설명 PO_OP_TYPE
VARCHAR(2)
-
SQL의 종류
-
입력값
-
'D' (Delete)
-
'UB' (Update Before)
-
'UA' (Update After)
-
'I' (Insert)
-
PO_OP_SEQ
NUMBER
-
실행 순번
-
입력값 : SEQUENCE.nextval
PO_OP_TIME
TIMESTAMP
-
DB I/O가 일어난 시간
-
기본값 : SYSTIMESTAMP
PO_OP_FLAGDEFAULT
VARCHAR(1)
-
해당 row의 복원작업이 수행됐는지 여부
-
입력값 : 'N', 'Y' (기본값: N)
BeforeImage 테이블을 생성하는 DDL의 예시는 다음과 같다.
CREATE TABLE EMP_BF_IMG ( EMPNO INT, ENAME VARCHAR(255), ... PO_OP_TYPE VARCHAR(2), PO_OP_SEQ NUMBER, PO_OP_TIME TIMESTAMP DEFAULT SYSTIMESTAMP, PO_OP_FLAG VARCHAR(1) DEFAULT 'N' );
Sequence를 별도로 기록하기 때문에 Tibero 기준으로 다음과 같은 DDL의 수행도 필요하다.
CREATE SEQUENCE EMP_BF_IMG_SEQ INCREMENT BY 1;
SEQUENCE명은 BeforeImage 테이블명에 "_SEQ"가 뒤에 붙은 이름을 가져야 한다.
-
-
데이터 오브젝트 팩토리 개발
BeforeImage 기능을 이용하려면 데이터 오브젝트 팩토리를 개발하는 경우 BeforeImage Option을 활성화시켜야 한다.
-
서비스 설정
BeforeImage 기능을 활성화한 데이터 오브젝트 팩토리를 서비스에서 사용하려면 서비스의 런타임 설정에서 SERVICE_{SERVICE_NAME}_BEFORE_IMAGE_ENABLE 값을 true로 설정해야 한다. 이 설정을 생략하면 BeforeImage 기능을 활성화한 데이터 오브젝트 팩토리를 사용해도 BeforeImage 기능을 이용할 수 없다.
4.5. 데이터 암호화 기능
데이터 오브젝트 팩토리를 통해 테이블에 DBIO를 수행하는 경우, 데이터를 암호화하고 복호화하는 기능이다.
데이터 오브젝트 팩토리는 데이터 오브젝트에 있는 값을 사용자가 지정한 암호화 알고리즘 혹은 암호화 클래스를 호출하여 암호화한 데이터로 INSERT / UPDATE를 수행하며, SELECT 쿼리를 수행할 경우 암호화된 데이터를 복호화하여 가져온다.
다음은 데이터 암호화 기능을 개발하는 과정에 대한 설명이다.
-
데이터 오브젝트에 암호화 속성 추가
암호화 기능을 사용하기 위해서는 데이터 오브젝트의 암호화 대상이될 멤버변수에 암호화 속성이 있어야 한다. 암호화 속성은 데이터 오브젝트를 개발할 당시 부여할수 있다.
-
암호화 키(key) 설정
암/복호화하는 경우 사용할 키는 ProObject Dev/OPS와 연동하여 설정하게된다.
암호화 키는 데이터 오브젝트 팩토리에 적용되는 암호화 설정의 종류에 따라 APPLICATION KEY와 SERVICEGROUP KEY로 나뉜다.
암호화 키 설명 APPLICATION KEY
애플리케이션 영역에서 공유되는 암호화 키이다.
이 키는 데이터 오브젝트 팩토리가 동작하는 서비스 그룹에 SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE 설정이 'FALSE’이면서 APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE 설정이 'TRUE’일 때 사용된다.
SERVICEGROUP KEY
서비스 그룹 영역에서 공유되는 암호화 키이다.
이 키는 데이터 오브젝트 팩토리가 동작하는 서비스 그룹에 SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE 설정이 'TRUE’인 경우 사용된다.
IN_OUT
IN / OUT 타입으로 모두 쓰이는 파라미터인 경우
두 키 모두 ProObject가 설치된 HOME 디렉터리의 특정 위치에 생성되며, 런타임에서는 해당 키를 읽어서 암복호화에 사용한다.
-
데이터 오브젝트 팩토리 암호화 설정 활성화
데이터 오브젝트 팩토리 암호화 설정은 APPLICATION / SERVICEGROUP LEVEL에서 제공된다.
설정은 총 3가지가 제공되며 각 설정은 챕터 초입부에 있는 애플리케이션 설정과 서비스 그룹 설정부분을 참고한다.
데이터 오브젝트의 멤버변수에 암호화 속성이 있어도, SERVICEGROUP_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE 혹은 APPLICATION_DATAOBJECTFACTORY_ENCRYPTMODULE_ENABLE 설정이 'TRUE’가 아닌 경우 암호화기능은 동작하지 않으니 유의한다.
-
데이터 오브젝트 팩토리 C/R/U/D API 호출
데이터 오브젝트 팩토리의 get, getForwardList, getScrollableList, getDataObjectList를 호출할 경우 DB 테이블에 있는 암호화된 데이터를 복호화한다. 이때 데이터는 반드시 ProObject의 암호화 기능을 통해서 암호화된 데이터이어야 한다.
데이터 오브젝트 팩토리의 add, update api를 호출할 경우 데이터 오브젝트 팩토리가 파라미터로 입력받은 데이터 오브젝트의 데이터를 암호화하여 DB 테이블에 입력한다.
5. DataDefinitionExecutor
DataDefinitionExecutor는 DDL(Data Definition Language) 문을 실행하기 위한 객체이다. SO나 BO의 로직에서 execute API를 이용하여 개발자로부터 직접 DDL 문자열을 입력받는다.
다음은 DataDefinitionExecutor를 사용하는 예시이다.
String create = "CREATE TABLE DUMP01 (ID NUMBER(4), NAME VARCHAR(50))"; DataDefinitionExecutor executor = DataDefinitionExecutor.getInstance("test"); // dataSource 명 전달 boolean isSuccess = executor.execute(create);
6. 프로시저 호출
ProObject에서는 Oracle/Tibero의 프로시저(Procedure)나 함수(Function)호출을 위해서 StoredProcedureCallFactory라는 유틸 클래스를 제공하고 있다. 이 클래스를 통해서 사용자는 프로시저나 함수를 호출하고 호출결과에 대한 응답을 처리할수 있다.
-
StroedProcedureCallFactory
StoredProcedureCallFactory 클래스는 프로시저나 함수를 실행시킬수 있는 객체 생성에 사용된다. 이 클래스를 이용하여 프로시저, 함수를 호출하는 경우 사용할 세션이나 데이터 소스를 선택할 수 있으며 트랜잭션 타입을 지정할 수 있다.
-
StoredProcedureCall
프로시저나 함수를 실행시키고 결과값을 받을수 있는 클래스다. 이 클래스를 이용하여 프로시저, 함수의 파라미터를 바인딩시키고, 프로시저와 함수를 실행시킨 다음 필요한 경우 결과값을 받아올수 있다.
-
CallParameter
StoredProcedureCall 객체에 파라미터를 입력할 때 사용되는 클래스이다. 파라미터의 SQL 타입과 IN / OUT / IN_OUT 파라미터 타입을 지정할수 있다.
-
SQL 타입
CallParameter에서 사용할 수 있는 SQL 타입은 CallParameter의 static 변수로 제공하고 있으며 그 목록은 다음과 같다.
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
FLOAT
REAL
DOUBLE
NUMERIC
DECIMAL
CHAR
VARCHAR
LONGVARCHAR
DATE
TIME
TIMESTAMP
BINARY
VARBINARY
LONGVARBINARY
NULL
OTHER
JAVA_OBJECT
DISTINCT
STRUCT
ARRAY
BLOB
CLOB
REF
DATALINK
BOOLEAN
ROWID
NCHAR
NVARCHAR
LONGNVARCHAR
NCLOB
SQLXML
CURSOR
이외에도 java.sql.Types에서 제공하는 타입을 사용할 수 있다.
-
IN / OUT 타입
프로시저 / 함수의 쿼리 파라미터는 IN / OUT 타입을 정해주어야 한다. CallParameter를 생성할 때 해당 타입을 CallParameter.ParameterType 값으로 입력해야 하며, ParameterType은 아래와 같이 3가지 타입으로 나뉜다.
타입 설명 IN
프로시저 / 함수의 입력값으로만 사용되는 파라미터인 경우
OUT
프로시저 / 함수의 실행 결과값을 받을 파라미터인 경우
IN_OUT
IN / OUT 타입으로 모두 쓰이는 파라미터인 경우
-
6.1. 개발 방법
ProObject에서 프로시저 호출을 하는 방법은 크게 3가지다.
-
StoredProcedureCall 객체 생성
StoredProcedureCall 객체를 생성하기 위해서는 StoredProcedureCallFactory의 newInstance API를 이용한다.
-
CallParameter로 파라미터 정보 입력
프시저나 함수의 파라미터는 파라미터의 SQL 타입과 파라미터의 종류가 INPUT / OUTPUT / IN_OUTPUT인지 선택해야 한다. SQL Type은 파라미터에 해당하는 타입을 java.sql.Types로 CallParameter 객체에 선언되어 있으니 참고한다.
파라미터 종류는 해당 파라미터가 INPUT용으로만 사용되는지, OUTPUT용으로만 사용되는지, INPUT/OUTPUT 모두 사용되는지를 설정한다.
-
프로시저 호출 후 StoredProcedureCall 객체에서 데이터 조회하기
StoredProcedureCall 클래스의 execute API를 이용해서 프로시저나 함수를 호출하고, 조회값 혹은 결과값이 필요한 경우 StoredProcedureCall 클래스에서 제공하는 getter API를 이용해야 한다(getter API는 Object / String / int / Long / ResultSet을 반환하는 메소드들이 있다).
// StoredProcedureCall 객체 생성 String procedureCallQuery = "~"; StoredProcedureCall procedure = StoredProcedureCallFactory.newInstance("datasourceName", procedureCallQuery); // CallParameter 입력 CallParameter empno = new CallParameter("empno", CallParameter.NUMERIC, CallParameter.ParameterType.IN, 1); CallParameter ename = new CallParameter("ename", CallParameter.VARCHAR, CallParameter.ParameterType.OUT); procedure.addParameter(empno); procedure.addParameter(ename); // 프로시저 호출 procedure.execute(); String ename = procedure.getString("ename");
6.2. StoredProcedureCallFactory API
StoredProcedureCallFactory가 제공하는 newInstance API를 통해서 프로시저 호출을 수행하는 CommonStoredProcedureCall 객체를 얻을 수 있다.
다음은 StoredProcedureCallFactory가 제공하는 API 목록이다.
-
StoredProcedureCall 객체 반환
6.2.1. newInstance
프로시저나 함수 호출을 위해서 필요한 StoredProcedureCall 객체를 반환하는 API이다.
파라미터에는 프로시저 / 함수 호출을 위한 쿼리 및 사용할 데이터소스 혹은 세션, 트랜잭션 종류를 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
newInstance API에 프로시저나 함수 호출을 위한 쿼리만 입력한다.
데이터소스는 proobject.json에 설정된 엔진 데이터소스를 사용하며, 트랜잭션은 기본은 로컬로 동작한다.
public static StoredProcedureCall newInstance(String query) public static StoredProcedureCall newInstance(String query, boolean isLocal)
StoredProcedureCall 객체가 프로시저나 함수 호출을 위해 사용할 데이터소스를 명시적으로 지정한다.
public static StoredProcedureCall newInstance(String dataSourceName, String query) public static StoredProcedureCall newInstance(String dataSourceName, String query, boolean isLocal)
같은 트랜잭션으로 묶이길 원하는 세션을 알고 있거나, 세션객체를 직접 들고 있을경우, StoredProcedureCall 객체가 사용할 세션을 지정한다.
public static StoredProcedureCall newInstance(Session session, String query) public static StoredProcedureCall newInstance(Session session, String query, boolean isLocal)
6.3. StoredProcedureCall API
StoredProcedureCall은 프로시저나 함수를 호출하고 결과값을 조회하는 객체이다.
다음은 StoredProcedureCall 객체가 제공하는 API 목록이다.
-
프로시저 / 함수 호출 쿼리 반환
-
파라미터 입력
-
파라미터 초기화
-
프로시저 / 함수 호출
-
JDBC 리소스 반환
-
바인딩 파라미터 입력
-
결과값 조회
-
세션 동기화 여부 확인
6.3.1. getQuery
StoredProcedureCall 객체를 생성할 때 StoredProcedureCallFactory의 newInstance에 입력한 프로시저 / 함수 호출 쿼리를 반환하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
프로시저 / 함수 호출을 위한 쿼리를 반환한다.
public String getQuery()
6.3.2. addParameter
프로시저 / 함수 호출 쿼리의 파라미터 정보를 입력한다.
파라미터 정보는 CallParameter 객체 형태로 입력한다. CallParameter의 parameterName 값은 호출 쿼리의 파라미터명과 동일해야한다. CallParameter에 대한 설명은 해당 항목 참고한다.
프로시저 / 함수 호출 쿼리에 존재하는 파라미터 정보를 CallParameter 형태로 입력한다. 쿼리에 존재하는 파라미터 갯수만큼 호출한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void addParameter(CallParameter param)
6.3.3. setParameters
프로시저 / 함수 호출 쿼리의 모든 파라미터 정보를 입력한다.
파라미터 정보는 CallParameter 객체 형태로 입력한다. CallParameter의 parameterName 값은 호출 쿼리의 파라미터명과 동일해야 한다. 프로시저 / 함수 호출 쿼리에 존재하는 파라미터 정보를 List 형태로 전달한다. List의 element는 CallParameter야 한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setParameters(List<CallParameter> params)
6.3.4. clearParameters
StoredProcedureCall 객체에 입력한 파라미터 정보를 초기화 한다.
StoredProcedureCall 객체에 입력한 CallParameter 정보를 모두 비워야하는 경우 사용한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void clearParameters()
6.3.5. execute
프로시저 / 함수를 호출한다.
StoredProcedureCall 객체에 skipUdatables 설정이 적용된 경우 프로시저 / 함수를 호출하기전에 StoredProcedureCall객체가 사용하고 있는 세션에 쌓여있는 addBatch 항목을 모두 실행시킨다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void execute() throws SQLException
6.3.6. close
StoredProcedureCall 객체가 생성한 CallableStatement 객체와 ResultSet 객체를 닫는다. StoredProcedureCall 객체를 사용을 종료하면 반드시 호출해야하는 API다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void close()
6.3.7. set
StoredProcedureCall 객체에 입력한 CallParameter의 바인딩 파라미터 값을 입력하는 API다.
새로운 CallParameter를 생성하는 기능이 아닌 이미 입력받은 CallParameter의 value 값만 변경한다. 값을 변경하려는 CallParameter의 이름과 변경하려는 값을 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void set(String parameterName, Object value)
6.3.8. get
프로시저 / 함수 호출 후 조회할 값이 있는 경우 파라미터명에 해당하는 값을 조회해서 Object 타입으로 반환하는 API다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public Object get(String parameterName) throws SQLException
파라미터 설명 String parameterName
조회하려는 파라미터 이름을 입력한다.
대상 파라미터가 CallParameter.ParameterType.OUT / CallParameter.ParameterType.IN_OUT으로 선언되어 있어야 한다.
6.3.9. getString
프로시저 / 함수 호출 후 조회할 값이 있는 경우 파라미터명에 해당하는 값을 조회해서 String 타입으로 반환하는 API다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public String getString(String parameterName) throws SQLException
파라미터 설명 String parameterName
조회하려는 파라미터 이름을 입력한다.
대상 파라미터가 CallParameter.ParameterType.OUT / CallParameter.ParameterType.IN_OUT으로 선언되어 있어야 한다.
6.3.10. getInt
프로시저 / 함수 호출 후 조회할 값이 있는 경우 파라미터명에 해당하는 값을 조회해서 int 타입으로 반환하는 API다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public int getInt(String parameterName) throws SQLException
파라미터 설명 String parameterName
조회하려는 파라미터 이름을 입력한다.
대상 파라미터가 CallParameter.ParameterType.OUT / CallParameter.ParameterType.IN_OUT으로 선언되어 있어야 한다.
6.3.11. getLong
프로시저 / 함수 호출 후 조회할 값이 있는 경우 파라미터명에 해당하는 값을 조회해서 long 타입으로 반환하는 API다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public long getLong(String parameterName) throws SQLException
파라미터 설명 String parameterName
조회하려는 파라미터 이름을 입력한다.
대상 파라미터가 CallParameter.ParameterType.OUT / CallParameter.ParameterType.IN_OUT으로 선언되어 있어야 한다.
6.3.12. getResultSet
프로시저 / 함수 호출 후 조회할 값이 있는 경우 파라미터명에 해당하는 값을 조회해서 ResultSet으로 반환하는 API다. 파라미터의 타입이 CURSOR인 경우 사용한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public ResultSet getResultSet(String parameterName) throws SQLException
파라미터 설명 String parameterName
조회하려는 파라미터 이름을 입력한다.
대상 파라미터가 CallPar ameter.ParameterType.OUT / CallParameter.ParameterType.IN_OUT으로 선언되어 있어야 한다.
6.3.13. isSkipUpdatables
StoredProcedureCall 객체가 프로시저 / 함수를 호출하기전 같은 세션을 사용하고 있는 데이터 오브젝트 팩토리 혹은 데이터 오브젝트 매퍼가 호출한 addBatch 내역을 실행시킬지 여부를 확인하는 API다.
해당 설정이 적용되어 있는 경우 StoredProcedureCall의 execute API를 호출하기전 세션에 addBatch한 내역을 모두 실행시킨뒤 프로시저 / 함수 호출 쿼리를 수행한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
SkipUpdatables의 현재 설정값을 반환한다.
public boolean isSkipUpdatables()
6.3.14. setSkipUpdatables
StoredProcedureCall 객체가 프로시저 / 함수를 호출하기전 같은 세션을 사용하고 있는 데이터 오브젝트 팩토리 혹은 데이터 오브젝트 매퍼가 호출한 addBatch 내역을 실행시킬지 여부를 설정하는 API다.
해당 설정이 적용되어 있는 경우 StoredProcedureCall의 execute API를 호출하기전 세션에 addBatch한 내역을 모두 실행시킨뒤 프로시저 / 함수 호출 쿼리를 수행한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
StoredProcedureCall 객체가 사용 중인 세션의 변경사항을 실행시킨후 프로시저 / 함수를 호출할지 여부를 결정한다.
public void setSkipUpdatables(boolean skipUpdatables)
6.4. CallParameter API
StoredProcedureCall 객체가 실행할 쿼리의 파라미터 정보를 담고있는 객체이다. 파라미터의 SQL 타입, IN / OUT 여부, 파라미터 값을 설정한다.
다음은 CallParameter 객체가 제공하는 API 목록이다.
-
생성자
-
파라미터 명 조회
-
파라미터 IN / OUT 여부 조회
-
파라미터 SQL 타입 조회
-
파라미터 값 조회
-
파라미터 값 설정
6.4.1. CallParameter
파라미터 이름, SQL 타입, 파라미터 IN /OUT 타입, 초기값을 설정한다.
파라미터 이름은 프로시저 / 함수 호출에 존재하는 파라미터명과 동일해야하며, SQL 타입은 java.sql.Types를 참조한다. 프로시저 / 함수 호출 쿼리에 파라미터의 정보를 입력한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
파라미터 타입이 OUT이거나 CallParameter 생성 시점에서 파라미터 값이 결정되지 않은 경우 사용한다.
public CallParameter(String parameterName, int sqlType, ParameterType inOut)
-
사용법 2)
CallParameter 객체를 생성하는 경우 파라미터 값을 같이 지정하는 경우 사용한다.
public CallParameter(String parameterName, int sqlType, ParameterType parameterType, Object value)
6.4.2. getParameterName
CallParameter를 생성하는 경우 지정한 파라미터 이름을 조회한다. 조회값은 String으로 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public String getParameterName()
6.4.3. getParameterType
CallParameter를 생성하는 경우 지정한 파라미터 타입을 반환한다. CallParameter.ParameterType형으로 반환하며, IN / OUT / IN_OUT 3가지 중 한 가지로 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public ParameterType getParameterType()
6.4.4. getSqlType
CallParameter를 생성하는 경우 지정한 SQL 타입을 반환한다. java.sql.Types에 해당하는 int 값으로 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public ParameterType getParameterType()
7. 쿼리 오브젝트
쿼리 오브젝트(QueryObject)는 사용자가 데이터 오브젝트 매퍼에서 사용할 SQL 문을 들고 있는 객체이다. 쿼리 오브젝트의 개발은 스튜디오를 통해 개발하며, 확장자는 .qo이다. 사용자는 사용할 SQL 문과 해당 SQL 문과 매핑할 데이터 오브젝트를 지정한다.
7.1. 개발 방법
본 절에서는 쿼리 오브젝트를 개발하는 과정에 대해서 설명한다.
7.1.1. 선행 개발 과정
쿼리 오브젝트를 개발하기 위해서는 반드시 데이터 오브젝트 생성 과정이 선행되어야 한다.
쿼리 오브젝트를 개발하기 위해서는 데이터 오브젝트가 선행 개발되어야 한다. 데이터 오브젝트는 흔히 쓰이는 개념인 DataTransferObject의 개념에서 확장되어 ORM의 Entity 개념을 포함하고 있다. ProObject에서는 데이터 오브젝트가 서비스 간의 input, output을 담당하며 DBIO와 FILE IO의 단위이다. DBIO로 사용하려는 데이터 오브젝트를 개발할 때는 SQL을 수행하려는 대상 테이블들의 view로 생각한다. 기본적인 데이터 오브젝트에 대한 개발 방법은 데이터 오브젝트를 참고한다.
데이터 오브젝트의 멤버변수로 다른 데이터 오브젝트를 포함하는 경우는 허용하지 않으므로 주의한다.
7.1.2. 수행로직 개발
쿼리 오브젝트 자체는 개발자가 입력한 쿼리의 정보만을 갖고 있는 객체이다. 그러므로 별도의 수행로직은 없으며 개발자가 쿼리에 대한 정보를 필요한 경우 쿼리 오브젝트 API를 이용하여 원하는 정보를 얻을수 있다.
-
SQL 입력
쿼리 오브젝트 자체는 개발자가 입력한 쿼리의 정보만을 갖고 있는 객체이다. 그러므로 별도의 수행로직은 없으며 개발자가 쿼리에 대한 정보를 필요한 경우 쿼리 오브젝트 API를 이용하여 원하는 정보를 얻을수 있다. 쿼리 오브젝트에 데이터 오브젝트 매퍼에서 사용할 쿼리를 입력한다. 쿼리는 여러 개를 입력가능하며, SO/BO에서 데이터 오브젝트 매퍼를 사용하는 경우 동작할 쿼리를 선택할 수 있다.
쿼리 오브젝트는 사용할 SQL을 미리 입력하고, SO나 BO에서 데이터 오브젝트 매퍼를 통해 사용할 SQL을 호출한다. 쿼리 오브젝트에 사용할 수 있는 SQL은 Full Query 또는 Dynamic Query이다. Query에 대한 설명은 DB 데이터 오브젝트 팩토리 구조를 참고한다.
입력할 수 있는 SQL의 개수는 제한이 없으나, 동일한 내용의 SQL을 중복해서 입력할 수 없다. 개발자는 C/R/U/D 타입별로 자신이 사용할 SQL을 쿼리 오브젝트에 입력할 수 있으며, 반드시 SQL에 해당하는 SQL ALIAS를 입력해야 한다. SQL ALIAS는 데이터 오브젝트 매퍼를 통해 개발자가 사용할 SQL을 선택할 때 SQL을 구분하는 단위가 되므로 반드시 사용자가 이해할 수 있는 의미를 담아 지정하도록 한다.
-
데이터 오브젝트 선택
데이터 오브젝트 팩토리의 경우 사용자가 지정한 모든 쿼리는 Target DO 한가지 타입에 맞춰서 매핑된다. 하지만 쿼리 오브젝트는 쿼리당 매핑할 데이터 오브젝트를 지정할 수 있다. 지정된 데이터 오브젝트 타입은 데이터 오브젝트 매퍼가 쿼리와 매핑하는 기본 데이터 오브젝트가 된다.
7.2. 쿼리 오브젝트 API
다음은 쿼리 오브젝트가 제공하는 API 목록이다.
-
쿼리 타입 반환
-
쿼리와 매핑되는 기본 데이터 오브젝트 타입 반환
-
쿼리에서 사용하는 테이블 목록
-
쿼리의 파라미터 정보 반환
7.2.1. getParameterInfo
현재 선택된 쿼리 오브젝트의 쿼리에서 사용되는 파라미터들의 정보를 반환하는 API이다.
쿼리에서 사용된 파라미터 정보를 java.util.Map으로 반환한다. Map의 Key는 파라미터명이며, Value는 파라미터 정보를 담고있는 com.tmax.proobject.dataobject.model.Parameter 객체이다. Parameter 객체는 파라미터의 이름, Class type, 파라미터 인덱스(index), 파라미터의 속성(조건, 값, 다이나믹 파라미터 여부)을 담고 있다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public Map<String, Parameter> getParameterInfo()
7.2.2. getResultType
현재 선택된 쿼리 오브젝트의 쿼리 종류를 판단하는 API이다. 데이터 오브젝트 매퍼에서 해당 API를 호출하여 쿼리와 매핑된 데이터 오브젝트 타입을 사용한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public Class<? extends DataObject> getResultType()
8. 데이터 오브젝트 매퍼
데이터 오브젝트 매퍼(DataObjectMapper)는 사용자가 개발한 쿼리 오브젝트의 쿼리를 실행하는 엔진 모듈이다. 데이터 오브젝트 팩토리가 개발할 때 지정된 쿼리만을 사용해야 한다면, 데이터 오브젝트 매퍼는 개발된 모든 쿼리 오브젝트의 쿼리들을 실행시킬 수 있다.
데이터 오브젝트 팩토리와 마찬가지로 DB 조회 결과는 데이터 오브젝트로 반환되며, 기본은 쿼리 오브젝트 개발 당시 지정된 쿼리의 반환 타입을 사용한다.
8.1. 개발 방법
본 절에서는 데이터 오브젝트를 개발하는 과정에 대해서 설명한다.
8.1.1. 선행 개발 과정
데이터 오브젝트 매퍼를 사용하여 개발하기 위해서는 반드시 다음의 과정이 선행되어야 한다.
-
데이터 오브젝트 생성
데이터 오브젝트 매퍼로 개발하기 위해서는 반드시 데이터 오브젝트가 선행 개발되어야 한다. 데이터 오브젝트 매퍼는 DB 조회 결과를 데이터 오브젝트 형태로 사용자에게 반환하고, 데이터 오브젝트의 데이터들을 DB에 추가, 수정하기 때문이다. 기본적인 데이터 오브젝트에 대한 개발 방법은 데이터 오브젝트를 참고한다.
데이터 오브젝트의 멤버변수로 다른 데이터 오브젝트를 포함하는 경우는 허용하지 않으므로 주의한다.
-
쿼리 오브젝트 생성
데이터 오브젝트 매퍼로 개발을 하기 위해서는 반드시 쿼리 오브젝트가 선행 개발되어야 한다. 데이터 오브젝트 매퍼는 쿼리 오브젝트에 존재하는 쿼리들을 실행시키는 것이므로 쿼리 오브젝트가 선행 개발되어 있지 않다면 쿼리를 수행할 수가 없기 때문이다. 기본적인 쿼리 오브젝트에 대한 개발 방법은 쿼리 오브젝트를 참고한다.
8.1.2. 수행로직 개발
데이터 오브젝트 매퍼를 이용한 개발은 다음의 과정으로 진행된다.
-
데이터소스 설정 및 객체 생성
데이터 오브젝트 매퍼는 ProObject에서 제공하는 기본 DI(Dependency Injection)의 대상이 아니다. 그러므로 개발자가 직접 DI 기능을 추가하고 데이터 오브젝트 매퍼의 객체를 생성해야 한다.
데이터 오브젝트 매퍼는 Constructor에 데이터소스명을 직접 입력받도록 되어 있으며, 데이터소스명이 입력되지 않는 경우 ProObject.xml에 설정된 기본 데이터소스를 사용한다. 사용하려는 데이터소스는 반드시 dbio_config.xml에 설정된 PairDataSource의 alias명과 일치해야 한다.
또한 데이터 오브젝트 매퍼의 객체를 생성할 때에 매퍼 객체가 사용할 데이터 오브젝트 타입을 Generic 타입으로 명시해줘야 한다. 데이터 오브젝트 매퍼는 객체를 생성할 때 입력받은 Generic 타입으로 DB 조회, 삽입, 수정 작업을 수행한다.
// ds1이라는 데이터소스를 사용하고, Emp를 반환 타입으로 갖는 데이터 오브젝트 매퍼 객체 생성 DataObjectMapper<Emp> mapper = new DataObjectMapper("ds1");
-
쿼리 선택
사용할 데이터소스명을 지정하여 DB 데이터 오브젝트 팩토리의 객체를 생성했다면 개발에 필요한 쿼리를 선택해야 한다.
데이터 오브젝트 매퍼는 쿼리 오브젝트의 enum 객체를 쿼리로 입력받는다. 데이터 오브젝트 매퍼의 setQuery API를 이용하여 데이터 오브젝트 매퍼가 사용할 쿼리를 설정해야 한다 . 선택한 쿼리는 쿼리 수행 API들(get, getForwardList, getScrollableList, getDataObjectList, add, update, delete)가 호출된 후에는 초기화되므로 쿼리를 반복 수행할 때는 반드시 쿼리 수행 API 호출 전에 쿼리 선택 API를 호출한다.
// 쿼리 오브젝트 BizAQuery의 SELECT1 쿼리 사용 mapper.setQuery(BizAQuery.SELECT1);
-
파라미터 입력
기존 Java JDBC에서는 쿼리 안에서 파라미터 값들을 '?'로 표시했으며, 파라미터 값은 setObject(int index)와 같이 개발자가 파라미터 위치를 지정해야 한다. 이러한 불편함을 해소하기 위해 데이터 오브젝트 매퍼는 쿼리 오브젝트에 Full Query의 경우 ':파라미터명' 으로, Dynamic Query의 경우 '#{파라미터명}', '#{do.파라미터명}'형태로 파라미터를 입력한다. 이에 대한 설명은 DB 데이터 오브젝트 팩토리 수행로직 개발 을 참고한다.
쿼리에 설정된 파라미터의 위치에 따라 DB 데이터 오브젝트 팩토리에 파라미터 값을 입력하는 방식은 두 가지로 나뉜다.
-
쿼리 조건(쿼리 내 WHERE 절에 해당하는 파라미터)에 위치한 파라미터 값을 입력하는 방법
데이터 오브젝트 매퍼에서는 setParameter(String name, Object value) API를 이용하여 파라미터를 입력한다.
mapper.setParameter("empno", 1);
-
데이터 삽입/수정에 대한 파라미터 값을 입력하는 방법
데이터 삽입/수정에 대한 파라미터란 INSERT 쿼리의 VALUES() 절에 포함되는 파라미터들이나 UPDATE 쿼리의 SET() 절에 포함되는 파라미터들을 뜻한다. 이러한 파라미터들은 Target DO에 값을 입력해야 한다. 즉, 파라미터명과 Target DO의 멤버변수명이 일치해야 한다.
쿼리 조건에 해당하는 파라미터와 데이터 삽입/수정에 해당하는 파라미터 값 입력방식이 다른 이유에 대해서 설명한다. 우선 쿼리 조건에 해당하는 파라미터의 경우 조건에 따라 다양한 이름으로 설정할 수 있다. 예를 들어 나이의 범위를 지정하는 조건의 경우 AGE라는 컬럼에 대해서 다음과 같이 쿼리를 구성할 수 있다.
AGE > :mimAge AND AGE < :maxAge
maxAge나 minAge와 같은 변수까지 모두 데이터 오브젝트에 선언하는 것은 불필요한 멤버변수를 늘리는 행위이므로 데이터 오브젝트가 아닌 DB 데이터 오브젝트 팩토리를 통해 파라미터 값을 입력받을 수 있다. 반면 데이터 삽입/수정 쿼리의 경우 입력받는 데이터 파라미터가 테이블의 컬럼과 정확하게 1:1로 일치한다. 예를 들어 "INSERT INTO EMP(EMPNO, ENAME, AGE) VALUES(~) "와 같은 쿼리에서 VALUES에 해당하는 파라미터들은 삽입하려는 테이블 컬럼에 1:1로 매핑하도록 제한된다.
-
-
쿼리 수행 API 호출
실행할 쿼리를 선택하고 파라미터까지 입력한 다음에는 DBIO 작업을 수행할 API를 호출한다. DBIO용 API는 C/R/U/D별로 나누어져 있으며, SELECT는 다시 단건 조회용 다건 조회용으로 나뉜다.
DBIO API를 호출하면 DB 데이터 오브젝트 매퍼에 설정했던 쿼리와 파라미터 정보가 초기화되므로 똑같은 쿼리를 반복수행한다고 해도 위에서 설명한 '2.쿼리 선택’과 '3.파라미터 입력’까지의 과정을 반복해야 한다.
8.2. 데이터 오브젝트 매퍼 API
다음은 데이터 오브젝트 매퍼가 제공하는 API 목록이다.
-
C/R/U/D Operataion 수행 전 쿼리 선택
-
SELECT 수행
-
단건조회 : get
-
데이터 갯수 조회 : getResultCount
-
-
INSERT, UPDATE, DELETE 수행
-
페이징 기능관련
-
쿼리 타임아웃
-
데이터 페치 관련
-
데이터 결과 관련
-
초기화 관련
8.2.1. add
데이터 삽입을 수행할 때 호출하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
테이블에 삽입하려는 데이터를 데이터 오브젝트로 입력받아, INSERT 쿼리를 수행한다. 파라미터 값에 따라 Java JDBC의 addBatch를 수행한다.
public int add(T insert, boolean immediate)
-
사용법 2)
addBatch를 기본으로 수행하는 API이다. 사용법1)에서 immediate 값을 false로 준것과 동일한 기능을 수행한다.
public void add(T insert)
-
사용법 3)
auto increased 속성을 지닌 column의 값을 구하기 위한 API이다. 입력값으로 넘겨준 데이터 오브젝 트의 필드에 auto increased column의 데이터를 담아준다.
public int add(T insert, String... autoIncreasedFields)
8.2.2. cleanUp
데이터 오브젝트 팩토리의 사용을 종료하고 데이터 오브젝트 팩토리가 사용한 모든 리소스를 반환한다. 일반적으로 서비스가 종료될 때 엔진에서 호출하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
addBatch된 내용을 모두 execute시키고 데이터 오브젝트 매퍼가 사용한 Java 리소스와 DB 리소스를 반납한다.
public void cleanUp()
-
사용법 2)
ForwardList와 ScrollableList는 사용자에게 데이터 조회값을 전달하기 위해서 Java ResultSet 객체와 Statement 객체를 들고 있다. 해당 DB 리소스를 명시적으로 반환하기 위해 사용하는 API이다.
public void cleanUp(ForwardList<T> forwardlist) public void cleanUp(ScrollableList<T> scrollablelist)
8.2.3. clearBatch
add, update, remove API들을 통해 addBatch된 내역들에 대한 DB 반영을 취소한다. clearBatch는 사용자 가 명시적으로 호출할 수도 있지만, 서비스가 실패한 경우 엔진 내부에서 호출한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void clearBatch()
8.2.4. executeAll
add, update, remove API들을 통해 addBatch된 내역들을 DB에 반영하는 기능을 수행한다.
executeAll은 사용자가 명시적으로 호출할 수도 있지만 다음의 경우 엔진 내부에서 호출하기도 한다.
-
서비스가 성공적으로 종료된 경우 트랜잭션 커밋을 수행하기 전에 엔진에서 호출한다.
-
get, getForwardList, getScrollableList, getDataObjectList를 통해서 데이터를 조회하기 전에 호출한다.
-
이전에 수행한 쿼리와 현재 수행하려는 쿼리가 다른 경우 호출한다. 메소드의 반환값으로 addBatch되었던 내역의 갯수를 사용자에게 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public int executeAll()
8.2.5. get
데이터 오브젝트 매퍼를 이용하여 단건 조회를 수행할때 호출하는 API이다.
호출하는 경우 데이터 조회 결과를 데이터 오브젝트 매퍼 객체 생성당시 Generic으로 지정한 타입으로 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public T get()
8.2.6. getDataObjectList
데이터 오브젝트 매퍼를 이용하여 다건 조회를 수행할때 호출하는 API이다.
쿼리 수행 결과를 ArrayList에 담아서 반환한다. 모든 조회 결과 값이 ArrayList에 담겨있기 때문에 결과 개수에 따라 memory overflow를 고려해야 한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public ArrayList<T> getDataObjectList()
8.2.7. getForwardList
데이터 오브젝트 매퍼를 이용하여 다건 조회를 수행할 때 호출하는 API이다. 조회 결과를 ForwardList에 매핑하여 반환한다. forward-only 조회를 수행한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public List<T> getForwardList()
8.2.8. getResultCount
데이터 조회 결과수를 확인하는 API이다.
get(), getForwardList(), getScrollableList(), getDataObjectList()처럼 조회 결과를 받는 것이 아니라 조회 결과의 개수를 long 값으로 반환받기 위한 API다. API 호출 전에 데이터 조회를 위해 쿼리 선택 및 조건값 을 설정하고, getResultCount()를 호출한다. 사용자가 선택한 쿼리에 "SELECT COUNT(*)" 쿼리를 붙여서 사용자가 선택한 쿼리의 결과 개수를 구한다. 실제로 조회용 쿼리가 실행되는 것을 참고한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public long getResultCount()
8.2.9. getScrollableList
데이터 오브젝트 매퍼를 이용하여 다건 조회를 수행할때 호출하는 API이다. 조회 결과를 ScrollableList에 매핑하여 반환한다. scroll-insensitive 조회를 수행한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public ScrollableList<T> getScrollableList()
8.2.11. reloadDataObjectConfig
ProManager를 통해 설정했던 데이터 오브젝트 팩토리의 설정들을 재설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void reloadDataObjectConfig()
8.2.12. remove
데이터 삭제를 수행할 때 호출하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
파라미터 값에 따라 Java JDBC의 addBatch를 수행한다.
public int remove(boolean immediate)
-
사용법 2)
addBatch를 기본으로 수행하는 API이다. 사용법1)에서 immediate 값을 false로 준것과 동일한 기능을 수행한다.
public void remove()
8.2.13. setFetchSize
데이터를 조회하는 경우 조회할 데이터의 페치 크기를 설정한다. API의 파라미터값을 이용하여 JavaJDBC 의 PreparedStatement의 setFetchSize를 호출한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setFetchSize(int fetchSize)
8.2.14. setPageNumber
페이징 기능을 이용하여 조회할 페이지 번호를 선택한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
public void setPageNumber(int pageNumber)
-
사용법 2)
페이징을 수행할 때 특정 필드로 정렬이 필요한 경우 파라미터를 통해서 정렬방법(ASC, DESC)과 정렬의 기준이될 필드를 선택할 수 있다. 기본 정렬 타입은 'ASC’이다.
public void setPageNumber(int pageNumber, String sortField, String sortType)
8.2.15. setPageQuery
ProObject의 페이징 기능은 Oracle, Tibero 기준으로 동작한다. Oracle, Tibero 이외의 DB에서 페이징을 원하는 경우 이 API를 이용한다. 예를 들어 DB2의 페이징 기능을 이용하려면 API의 파라미터로 "LIMIT"을 설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setPageQuery(String pageQuery)
8.2.16. setPageSize
페이징 기능을 사용하여 데이터를 조회했을 때 페이지의 크기를 설정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setPageSize(int size)
8.2.17. setQuery
데이터 오브젝트 매퍼가 사용할 쿼리를 선택하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
API의 파라미터로 쿼리 오브젝트의 쿼리를 넘겨준다.
public DataObjectMapper<T> setQuery(QueryInfo query)
-
사용법 2)
쿼리 오브젝트에 지정된 반환 타입과 데이터 오브젝트 매퍼의 Generic 타입이 다른 경우 setQuery API에 데이터 오브젝트 매퍼에 지정한 Generic 타입을 넘겨줘야 한다.
public DataObjectMapper<T> setQuery(QueryInfo query, Class<T> returnType)
8.2.18. setParameter
쿼리 조건에 해당하는 파라미터의 값을 설정할 때 사용하는 API다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public DataObjectMapper<T> setParameter(String parameterName, Object value)
8.2.19. clearParameter
setParameter API를 사용해 입력한 파라미터 정보를 초기화한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void clearParameter()
8.2.20. setTimeout
쿼리 수행시간에 제한을 설정할 수 있는 API이다.
API의 파라미터 값을 이용하여 쿼리 수행 전 Java JDBC의 PreparedStatement에 setQueryTimeout을 호출한다.
설정된 값과 WAS의 설정값, 서비스 타임아웃까지 남은 시간중 비교하여 제일 작은 값을 쿼리 타임아웃 값으로 사용한다. 단, 입력받은 값이 '0’인 경우, 사용자가 명시적으로 쿼리 타임아웃 시간을 무제한으로 지정한것이기 때문에, 쿼리 타임아웃 시간을 '0’으로 설정한다.
해당 API나 설정을 통해 쿼리타임아웃 시간을 지정하지 않은 경우, WAS의 기본 설정값과 서비스 타임아웃 시간까지 남은 시간중 제일 작은 시간을 쿼리 타임아웃 시간으로 결정한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setTimeout(Integer timeout)
8.2.21. update
데이터 수정을 수행할 때 호출하는 API이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
테이블에 수정하려는 데이터를 데이터 오브젝트로 입력받아 UPDATE 쿼리를 수행한다. 파라미터 값에 따라 JDBC의 addBatch를 수행한다.
public int update(T update, boolean immediate)
-
사용법 2)
addBatch를 기본으로 수행하는 API이다. 사용법1)에서 immediate 값을 false로 준것과 동일한 기능을 수행한다.
public void update(T update)
-
사용법3)
auto increased 속성을 지닌 column의 값을 구하기 위한 API이다. 입력값으로 넘겨준 데이터 오브젝 트의 필드에 auto increased column의 데이터를 담아준다.
public int update(T update, String... autoIncreasedFields)
8.2.22. setEmptyResultCheck
SELECT 쿼리를 이용하여 데이터를 조회할 때 조회 여부를 확인하고, 조회값이 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setEmptyResultCheck(boolean emptyResultCheck)
파라미터 설명 boolean singleResultCheck
-
true : SELECT 쿼리를 수행하는 경우 조회 여부를 확인하고, 조회값이 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
-
false : 조회값 존재 여부를 확인하지 않는다.
-
8.2.23. setEmptyResultCheckForUpdate
INSERT, UPDATE, DELETE 쿼리를 수행할 때 쿼리가 적용된 ROW가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
addBatch로 수행되는 쿼리나 executeBatch가 수행되는 쿼리에 대해서는 설정을 적용하지 않는다.
boolean 값을 파라미터로 입력받으며, 파라미터 값에 따라서 설정 적용여부가 결정된다. 데이터 오브젝트 매퍼의 add, update, remove API 호출시 적용되는 옵션이며, add(input, false), update(input, false), remove(input, false) 혹은 add(input), update(input), remove(input)과 같이 JDBC의 addBatch 기능을 적용할때에는 옵션을 적용하지 않는다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setEmptyResultCheckForUpdate(boolean emptyResultCheckForUpdate)
파라미터 설명 boolean emptyResultCheckForUpdate
-
true : INSERT, UPDATE, DELETE 쿼리를 수행하는 경우 쿼리가 수행된 ROW 수를 확인하고, 적용된 ROW가 없는 경우 com.tmax.proobject.dataobject.exception.EmptyResultException이 발생한다.
-
false : 쿼리가 수행된 ROW 수를 확인하지 않는다.
-
8.2.24. setSingleResultCheck
데이터 오브젝트 매퍼의 get API를 이용해서 데이터 조회시, 조회 여부를 확인하고, 조회값 두개 이상 존재하는 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
boolean 값을 파라미터로 입력받으며, 파라미터 값에 따라서 설정 적용여부가 결정된다. 데이터 오브젝트 매퍼의 get API를 이용해서 SELECT 쿼리를 수행시키는 경우에만 적용되며, getForwardList, getScrollableList, getDataObjectList API를 사용할때는 적용되지 않는다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setSingleResultCheck(boolean singleResultCheck)
파라미터 설명 boolean singleResultCheck
-
true : SELECT 쿼리를 수행하는 경우 조회 여부를 확인하고, 조회 결과가 두 건 이상 존재하는 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
-
false : 조회 결과 조회된 데이터의 갯수를 확인하지 않는다.
-
8.2.25. setMaxRows
SELECT를 이용하여 데이터 조회시, 조회할수 있는 최대 ROW갯수를 제한한다.
파미터 값에 따라 com.tmax.proobject.dataobject.exception.MaxRowException을 발생시키기도 하며, JDBC 설정을 통해 지정된 ROW수만을 조회하게 할수 있다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
getForwardList, getScrollableList, getDataObjectList API 사용시 조회된 데이터의 갯수를 제한한다.
설정된 정수값을 넘어서는 데이터가 조회된 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
public void setMaxRows(int maxRows)
파라미터 설명 int maxRows
조회할 row의 상한선을 입력한다.
-
사용법 2)
getForwardList, getScrollableList, getDataObjectList API 사용시 조회된 데이터의 갯수를 제한한다.
파라미터 값에 따라 설정된 정수값을 넘어서는 데이터가 조회된 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
public void setMaxRows(int maxRows, boolean throwException)
파라미터 설명 int maxRows
조회할 row의 상한선을 입력한다.
boolean throwException
-
true : maxRows 이상의 데이터가 조회된 경우 com.tmax.proobject.dataobject.exception.MaxRowException이 발생한다.
-
false : java.sql.Statement의 setMaxRows api에 사용자가 설정한 maxRows 값을 설정한다.
-
9. 파일 데이터 오브젝트 팩토리
본 절에서는 File IO를 수행하는 파일 데이터 오브젝트 팩토리에 대한 개념과 개발방법에 대해 설명한다.
9.1. 구조
파일 데이터 오브젝트 팩토리는 Fixed Length, Delimiter, XML 3가지 방식으로 파일 읽기, 쓰기 작업을 수행하는 객체다.
파일 데이터 오브젝트 팩토리는 사용자가 지정한 파일에 대해서 라인 단위로 데이터를 읽고 쓸 수 있며, 읽어들인 데이터는 데이터 오브젝트로 객체 매핑이 되고, 데이터 오브젝트 객체를 입력받아 해당 객체의 데이터를 파일에 쓸 수 있다.
파일 데이터 오브젝트 팩토리는 헤더와 테일 기능을 이용하여, 파일의 처음과 마지막에 사용자가 원하는 서식으로 내용을 추가할 수 있는 기능을 제공한다. ProStudio를 통해 바디(body)가 될 파일 데이터 오브젝트 팩토리에 헤더와 테일이 될 파일 데이터 오브젝트 팩토리를 지정한다. 바디 파일 데이터 오브젝트 팩토리에 getHeader()와 getTail() API를 이용하여 헤더와 테일 객체를 얻어올 수 있다.
9.2. 개발 방법
본 절에서는 파일 데이터 오브젝트 팩토리를 개발하는 과정에 대해서 설명한다.
9.2.1. 선행 개발 과정
파일 데이터 오브젝트 팩토리를 개발하기 위해서는 반드시 선행되어야 하는 절차가 필요하다.
-
데이터 오브젝트 생성
데이터 오브젝트 팩토리를 개발하기 위해서는 반드시 기반이 될 데이터 오브젝트가 존재해야 한다.
-
데이터 오브젝트 선택
데이터 오브젝트 팩토리의 기반이 될 데이터 오브젝트를 선택한다. 파일 데이터 오브젝트 팩토리는 선택된 데이터 오브젝트 형태로 파일 내용을 읽고, 데이터 오브젝트의 내용을 파일의 라인 하나로 기록한다.
-
파일 데이터 오브젝트 객체 생성
파일 데이터 오브젝트 객체의 Constructor에 파일 경로를 입력하여 데이터 오브젝트 팩토리 객체를 생성한다.
-
기능 수행
get, add API를 이용하여 파일의 내용을 읽고 쓰는 동작을 수행한다. DB 데이터 오브젝트 팩토리에서 제공하는 update, delete는 파일 데이터 오브젝트 팩토리에서 제공되지 않는다.
9.2.2. 개발 과정
본 절에서는 실제 파일 데이터 오브젝트의 활용 샘플 코드를 통해서 파일 데이터 오브젝트 팩토리를 사용하는 방법에 대해서 설명한다.
파일 데이터 오브젝트를 이용한 개발은 다음의 과정으로 진행된다.
-
파일 데이터 오브젝트 팩토리 객체 생성 및 파일 설정
//* SampleData 파일을 이용하여 파일 입출력을 하기위한 파일 데이터 오브젝트 팩토리 객체 생성 SampleFileDataObjectFactory factory = new SampleFileDataObjectFactory(); factory.setFile(new File("C:\Users\Tmax\Desktop\SampleData")); //* 기존 데이터 내용을 지우고 새로 파일을 쓰고 싶은 경우 Constructor에 false 값을 준다. //* factory.setFile(new File("C:\Users\Tmax\Desktop\SampleData"),false);
-
파일 데이터 오브젝트 팩토리 압축 파일 설정
//* 압축 파일 설정 factory.applyZipFile(true);
-
파일 데이터 오브젝트의 I/O 대상이 바이너리 파일인 경우 설정
//* 바이너리 파일 설정 factory.applyBinaryFile(true);
-
파일 데이터 오브젝트 팩토리 인코딩 캐릭터 셋 설정
factory.setCharSet("UTF-8"); //* 혹은 factory.setCharSet("EUC-KR");
-
파일 데이터 오브젝트 팩토리 개행문자 설정
//* \n factory.setNewLine(true); // or factory.setNewLineLength(1); //* \r\n factory.setNewLine(false); // or factory.setNewLineLength(2);
-
파일 데이터 오브젝트 팩토리 파일 읽기
SampleDataObject output = factory.get(); System.out.println(output);
-
파일 데이터 오브젝트 팩토리 여러 행 읽기
//* 파일의 처음부터 끝까지 루프를 돌면서 한 라인씩 읽는다. ForwardList>SampleDataObject< output = factory.getForwardList(); for(SampleDataObject item : output) { System.out.println(item); }
-
파일 데이터 오브젝트 팩토리 객체 파일 쓰기
SampleDataObject item = new SampleDataObject(); item.setEmpno(1); item.setEname("Jhon"); item.setSal(100); item.setDeptno(10); factory.add(item); //* 명시적으로 버퍼를 비우고 싶다면 factory.flush();
-
파일 데이터 오브젝트 팩토리 헤더 파일 읽기
SampleHeaderItem headerItem = factory.getHeader().get(); System.out.println(headerItem);
-
파일 데이터 오브젝트 팩토리 헤더 파일 쓰기
SampleHeaderItem headerItem = new SampleHeaderItem(); headerItem.setMgr(10); headerItem.setHireDate("2018-03-31"); factory.getHeader().add(headerItem);
-
파일 데이터 오브젝트 팩토리 테일 파일 읽기
SampleTailItem tailItem = factory.getTail().get(); System.out.println(tailItem);
-
파일 데이터 오브젝트 팩토리 테일 파일 쓰기
SampleTailItem tailItem = new SampleTailItem(); tailItem.setDname("lab1"); tailItem.setPhoneNumber("010-0000-0000"); factory.getTail().add(tailItem);
9.3. 파일 데이터 오브젝트 팩토리 API
파일 데이터 오브젝트 팩토리를 개발하기 위해서 다음의 API를 제공한다.
9.3.1. add
입력받은 데이터 오브젝트의 데이터들을 파일 데이터 오브젝트의 파일 형식에 따라 한 라인으로 파일에 기록한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void add(DataObject)
9.3.2. applyBinaryFile
FILE I/O의 대상이 바이너리 파일인지 텍스트 파일인지 선택하기 위한 API이다.
기본적으로 FILE DOF는 setFile로 입력받은 파일은 텍스트 파일로 취급한다. FILE I/O 대상이 바이너리 파일이면 파라미터로 'true’를 텍스트 파일이면 파라미터로 'false’를 전달한다. ProObject에서 바이너리 파일은 Fixed Length일때만 사용 가능하다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void applyBinaryFile(boolean isBinary)
9.3.3. applyZipFile
FILE I/O의 대상이 압축파일인 경우를 설정하기 위한 API이다. 기본적으로 FILE DOF는 setFile로 입력받은 파일은 일반 파일로 취급한다. FILE I/O 대상이 압축파일인 경우 파라미터로 'true’를 전달한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
void applyZipFile(boolean isZipFile)
9.3.4. cleanUp
파일 데이터 오브젝트 팩토리가 사용한 파일 리소스와 팩토리의 리소스들을 모두 해제한다. 헤더와 테일이 존재할 경우 헤더 테일의 리소스도 해제한다. 일반적으로 서비스를 종료하는 경우 자동으로 호출되는 메소드이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void cleanUp(void)
9.3.5. flush
파일 입력 작업 중 버퍼에 남은 내용을 파일에 기록한다. ProObject에서는 서비스를 종료하는 경우 자동으로 호출되는 함수이다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void flush(void)
9.3.6. get
파일의 내용 하나를 읽어서 데이터 오브젝트로 반환받는다. 파일의 내용은 데이터 오브젝트의 각 멤버변수에 저장된다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public DataObject get(void)
9.3.7. getCharSet
현재 파일 데이터 오브젝트 팩토리가 사용하는 인코딩 캐릭터 셋을 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public String getCharSet(void)
9.3.8. getFile
현재 파일 데이터 오브젝트 팩토리의 입출력 대상이되는 파일 객체를 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public File getFile(void)
9.3.9. getForwardList
DB 데이터 오브젝트의 getForwardList와 동일한 기능을 수행한다. Iterator, for-each를 수행하면서 파일의 내용을 순차적으로 읽어서 데이터 오브젝트로 반환한다. 또는 ForwardList의 get() API를 호출하는 경우 파일의 한 라인을 데이터 오브젝트로 반환한다.
해당 API는 호출되는 시점부터 파일을 끝까지 읽기 때문에, Header - Body - Tail 구조와 같이 서로 다른 포맷으로 기록된 파일에서는 사용을 주의해야한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public ForwardList<DataObject> getForwardList(void)
9.3.10. hasNext
파일 데이터 오브젝트 팩토리가 파일을 Read 중일 경우 현재 읽고 있는 파일에 더 읽을수 있는 데이터가 있는지 확인한다. API 호출 결과 반환된 boolean 데이터로 현재 read 중인 파일을 전부 읽었는지 확인할수 있다.
다음 API의 사용법에 대한 설명이다.
-
사용법
public boolean hasNext()
반환값 설명 true
현재 파일 커서에서 더 읽을수 있는 데이터가 존재한다.
false
더이상 읽을수 있는 데이터가 존재하지 않는다.
9.3.11. getHeader
현재 파일 데이터 오브젝트 팩토리의 헤더로 지정된 파일 데이터 오브젝트 팩토리를 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public FileDataObjectFactory getHeader(void)
9.3.12. getTail
현재 파일 데이터 오브젝트 팩토리의 테일로 지정된 파일 데이터 오브젝트 팩토리를 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public FileDataObjectFactory getTail(void)
9.3.13. isBinaryFile
현재 FILE DOF의 FILE I/O 대상이 바이너리 파일인지 텍스트 파일인지를 반환한다. 바이너리 파일인 경우 'true’를 반환하고, 텍스트 파일인 경우 'false’를 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
boolean isBinaryFile()
9.3.14. isZipFile
현재 FILE DOF의 FILE I/O 대상이 압축 파일인지 여부를 반환한다. 압축 파일인 경우 'true’를 반환하고, 일반 파일인경우 'false’를 반환한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
boolean isZipFile()
9.3.15. setCharSet
파일 데이터 오브젝트 팩토리에서 사용할 인코딩 캐릭터 셋을 설정한다.
입력값은 String으로 전달하며 'UTF-8’과 'EUC-KR' 둘 중 하나로 지정할 수 있다. 파일 데이터 오브젝트 팩토리에 헤더와 테일이 존재하면, 인코딩 캐릭터 셋을 동일하게 맞춘다.
다음은 API의 사용법에 대한 설명이다.
-
사용법
public void setCharSet(String)
9.3.16. setFile
파일 데이터 오브젝트가 파일 입출력을 수행해야 하는 대상을 파일 객체로 전달한다.
setFile API 호출을 하면 이전에 호출하였던 applyBinaryFile, applyZipFile로 지정했던 파일 형태가 초기화되므로 참고하도록한다. setFile 호출 이후 바이너리 파일이나 압축 파일에 대한 설정을 추가해야 한다.
다음은 API의 사용법에 대한 설명이다.
-
사용법 1)
파일 데이터 오브젝트 팩토리를 생성하는 경우 Constructor에 파일 경로를 입력한 경우 팩토리 내부에서 자동으로 호출되는 메소드이다. 이 메소드는 기존 파일 내용에 이어서 입출력 작업을 하는 동작을 위해 호출된다.
public void setFile(File)
-
사용법 2)
기본 기능은 setFile(File)과 동일하지만 boolean 값에 따라 파일 입출력을 이어서 하거나 새로 할 수 있다. boolean 값이 true인 경우 파일 입출력을 이어서 하고, false인 경우 파일을 입력할 때 새로운 파일을 만들어서 사용한다.
public void setFile(File, boolean)
10. 비동기 데이터 오브젝트
Complex Service에서의 데이터 입출력은 데이터 오브젝트 팩토리 객체를 생성한 후 팩토리의 메소드를 호출하기만 하면 된다.
데이터 오브젝트 팩토리의 메소드는 입출력 관련 API를 호출하면 Blocking 방식으로 I/O를 수행하게 된다. 다만 이벤트 서비스에서는 싱글 스레드로 작업이 수행되며, 싱글 스레드는 서비스 스케줄링 및 여러 이벤트 처리를 함께 담당하고 있기 때문에 Blocking 방식으로 I/O를 처리할 경우 심각한 성능의 저하를 가져올 확률이 높다. 하지만 데이터 입출력이 없는 서비스는 드물며, 흔히 말하는 간단한 서비스들은 데이터가 적고 간단한 I/O를 처리하는 서비스인 경우가 많다.
따라서 ProObject에서는 이러한 I/O를 처리하기 위해 비동기 데이터 오브젝트(AsyncDataObject, 이하 AsyncDO)라는 유틸 클래스를 두어 Non-Blocking 방식으로 I/O를 처리한다.
AsyncDO를 사용하기 위해서는 이미 데이터 오브젝트와 데이터 오브젝트 팩토리가 모두 작성되어 있어야 한다. AsyncDO는 기능을 수행할 때 마다 ServiceWorkThread가 할당되며 EventServiceManager를 통한 acall과 rcall을 호출한것과 동일한 기능을 수행한다.
10.1. 비동기 데이터 오브젝트 API
비동기 데이터 오브젝트를 위해 execute API를 제공한다.
10.1.1. execute
데이터 조회를 비동기 수행하기 위한 메소드이다.
-
사용법
public static void execute(DBDataObjectFactory<T> dbDo) public static void execute(DBDataObjectFactory<T> dbDo, DataObject dataobject, DBType type) public static void execute(DBDataObjectFactory<T> dbDo, String serviceMethodNameOnResponse) public static void execute(DBDataObjectFactory<T> dbDo, DataObject dataobject, DBType type, String serviceMethodNameOnResponse) public static void execute(DBDataObjectFactory<T> dbDo, String serviceMethodNameOnResponse, String serviceMethodNameOnError) public static void execute(DBDataObjectFactory<T> dbDo, DataObject dataobject, DBType type, String serviceMethodNameOnResponse, String serviceMethodNameOnError)
파라미터 설명 dbDo
수행할 쿼리가 선택된 데이터 오브젝트 팩토리이다.
dataobject
INSERT, UPDATE 쿼리를 수행하는 경우 파라미터로 전달할 데이터 오브젝트 객체이다.
type
DOF가 수행할 타입을 선택한다.
-
SELECT
-
INSERT
-
UPDATE
-
DELETE
serviceMethodNameOnResponse
DB 작업을 수행한 후 응답을 처리할 메소드명이다.
serviceMethodNameOnError
비동기 작업 중 예외가 발생한 경우 처리할 메소드명이다.
-
10.2. AsyncDBOperationResult
AsyncDO의 execute api 호출하는 경우 serviceMethodNameOnResponse 값을 입력했다면, DB I/O 작업이 끝난 후 사용자가 지정한 메소드로 서비스에 재진입하게 된다. 이때 사용자는 반드시 메소드의 파라미터로 com.tmax.proobject.engine.system.dto.async.AsyncDBOperationResult를 지정해야 한다.
AsyncDBOperationResult에는 사용자의 쿼리 조회 결과에 대한 DataObject 목록이나 쿼리수행 결과 반영된 row count 수가 들어 있다.
-
멤버변수
멤버변수 설명 resultList
데이터 오브젝트를 담고 있는 List 객체이다. SELECT를 수행한 경우 결과 값이 List에 담겨 있다.
resultCnt
쿼리 수행 결과가 담겨 있다.
-
SELECT의 경우 : 조회한 do 갯수
-
INSERT, UPDATE, DELETE인 경우 : 수행된 ROW 수
-
10.3. 개발 과정
다음은 AsyncDO를 사용하는 과정에 대한 설명이다.
-
이벤트 서비스 생성
데이터 오브젝트를 비동기식으로 사용하기 위해서는 이벤트 서비스를 생성해야 한다.
public class AsyncJDBCTest implements EventServiceObject { @Override public Object service(Object input, UserContext userContext) throws Throwable { return null; } @PostEventResponse public Object response(Object input, UserContext userContext) { return input; } }
-
데이터 조회
다음은 비동기로 SELECT 쿼리를 수행 후 조회 정보를 응답 메소드에서 처리하는 예제이다. 데이터 조회가 완료되면 사용자가 지정한 메소드에 진입하게 되고, AsyncDBOperationResult로부터 결과값 조회와 조회 건수를 확인할 수 있다.
public class AsyncJDBCTest implements EventServiceObject { @Override public Object service(Object input, UserContext userContext) throws Throwable { ServiceLogger logger = (ServiceLogger) ServiceLogger.getLogger(); logger.info("****************************************************************"); logger.info(" ASYNC DOF SELECT "); logger.info("****************************************************************"); StringDataObject output = new StringDataObject(); //-- (1) 쿼리를 수행시킬 데이터소스를 입력한다. --// EmpDO_Factory factory = new EmpDO_Factory("tibero6"); //-- (2) 수행할 쿼리를 선택한다. --// factory.setFullQuery(FULLQUERY.SELECT1); //-- (3) 쿼리에 조건을 입력해야 한다면 조건값을 입력한다. --// factory.setEmpno(1); //-- (4) AsyncDataObject 클래스의 execute API를 호출하여 DOF와 리턴받을 메소드명을 입력한다. --// AsyncDataObject.execute(factory, "response"); return output; } @PostEventResponse public Object response(AsyncDBOperationResult input, UserContext userContext) { ServiceLogger logger = (ServiceLogger) ServiceLogger.getLogger(); logger.info("****************************************************************"); logger.info(" ASYNC DOF SELECT RETURN "); logger.info("****************************************************************"); StringDataObject output = new StringDataObject(); output.setValue("TEST > ASYNCDOFSELECTRETURN"); //-- (5) AsyncDBOperationResult의 resultList 멤버변수에 조회결과가 담겨 있다. --// EmpDO result = (EmpDO) input.getResultList().get(0); logger.info("[ASYNCDOFSELECTRETURN] result -> \n" + result.toString()); return output; } }
-
데이터 추가
다음은 비동기로 INSERT 쿼리를 수행하는 예제이다.
public class AsyncJDBCTest implements EventServiceObject { @Override public Object service(Object input, UserContext userContext) throws Throwable { ServiceLogger logger = (ServiceLogger) ServiceLogger.getLogger(); logger.info("****************************************************************"); logger.info(" ASYNC DOF INSERT "); logger.info("****************************************************************"); StringDataObject output = new StringDataObject(); //-- (1) 쿼리를 수행시킬 데이터소스를 입력한다. --// EmpDO_Factory factory = new EmpDO_Factory("tibero6"); //-- (2) 수행할 쿼리를 선택한다. --// factory.setFullQuery(FULLQUERY.INSERT1); //-- (3) 삽입할 데이터를 입력한다. --// EmpDO insert = new EmpDO(); insert.setEmpno(1); insert.setEname("HONG GIL DONG); ... //-- (4) AsyncDataObject클래스의 execute API를 호출하여 사용할 DOF, 삽입할 데이터, 수행할 쿼리 타입을 입력한다. --// AsyncDataObject.execute(factory, insert, DBType.INSERT); return output; } }
-
데이터 수정
다음은 비동기로 UPDATE 쿼리를 수행하는 예제이다.
public class AsyncJDBCTest implements EventServiceObject { @Override public Object service(Object input, UserContext userContext) throws Throwable { ServiceLogger logger = (ServiceLogger) ServiceLogger.getLogger(); logger.info("****************************************************************"); logger.info(" ASYNC DOF UPDATE "); logger.info("****************************************************************"); StringDataObject output = new StringDataObject(); //-- (1) 쿼리를 수행시킬 데이터소스를 입력한다. --// EmpDO_Factory factory = new EmpDO_Factory("tibero6"); //-- (2) 수행할 쿼리를 선택한다. --// factory.setFullQuery(FULLQUERY.UPDATE1); //-- (3) 수정할 데이터를 입력한다. --// EmpDO update = new EmpDO(); update.setEname("HONG GIL DONG"); update.setJob("Manager"); factory.setEmpno(1); ... //-- (4) AsyncDataObject클래스의 execute API를 호출하여 사용할 DOF, 수정할 데이터, 수행할 쿼리 타입을 입력한다. --// AsyncDataObject.execute(factory, update, DBType.UPDATE); return output; } }
-
데이터 삭제
다음은 비동기로 DELETE 쿼리를 수행하는 예제이다.
public class AsyncJDBCTest implements EventServiceObject { @Override public Object service(Object input, UserContext userContext) throws Throwable { ServiceLogger logger = (ServiceLogger) ServiceLogger.getLogger(); logger.info("****************************************************************"); logger.info(" ASYNC DOF DELETE "); logger.info("****************************************************************"); StringDataObject output = new StringDataObject(); //-- (1) 쿼리를 수행시킬 데이터소스를 입력한다. --// EmpDO_Factory factory = new EmpDO_Factory("tibero6"); //-- (2) 수행할 쿼리를 선택한다. --// factory.setFullQuery(FULLQUERY.DELETE1); //-- (3) 삭제할 쿼리 조건을 입력한다. --// factory.setEmpno(1); //-- (4) AsyncDataObject클래스의 execute API를 호출하여 사용할 DOF, 수행할 쿼리 타입을 입력한다. --// AsyncDataObject.execute(factory, null, DBType.DELETE); return output; } }
11. 데이터 오브젝트 캐시
ProObject는 데이터 오브젝트 팩토리의 DB 작업을 수행하는데 필요한 시간을 줄임으로써, 좀더 나은 성능 향상을 사용자에게 제공하기 위해 세션 레이어의 캐시 기능을 제공한다. 캐시는 데이터 오브젝트의 키(key) 필드 값을 기준으로 데이터 오브젝트 단위로 캐싱을 한다. 그러므로 키 필드가 없는 경우 캐시 기능은 동작하지 않으므로 주의한다.
또한 system.properties에 SYSTEM_DATAOBJECT_CACHE_ENABLE 항목의 값이 true로 설정되어 있어야 캐시 기능이 동작한다. 해당 옵션이 true에서 false로 변경되면 cache invalidate를 수행한다.
본 절에서는 ProObject에서 캐시를 사용하기 위한 환경 설정과 동작 범위, 방식에 대해서 설명한다.
11.1. 캐시 사용이 가능한 DO 생성
ProObject에서 캐시 기능을 사용하기 위해서는 데이터 오브젝트에 키(key) 속성이 있는 필드가 존재해야 한다. key 속성은 ProManager를 통해 메타에 추가할 수 있다. 이때 지정하는 키는 테이블의 키가 아닌 ProObject가 캐싱을 데이터 오브젝트의 기준으로 ProManager의 메타에서 키 속성을 지정한 필드가 기준이 된다.
ProStudio를 통해서 DO를 생성하는 경우 반드시 키 속성을 지닌 메타를 사용하여 DO를 생성해야 한다. 키는 DO가 대응하는 테이블의 실제 키 컬럼에 해당하는 메타를 사용해도 되고, 사용자 임의의 키 필드를 선택해도 가능하다. 두 개 이상의 키 필드를 지정할 수도 있다.
11.2. 세션 캐시
세션 캐시는 트랜잭션 단위의 캐시로 한 서비스 내에서의 캐시를 보장한다. 이 기능을 사용하기 위해서는 데이터 오브젝트에 키(key) 필드가 명시되어 있어야 하며 애플리케이션 프로퍼티(APPLICATION_DATAOBJECT_CACHE)에 캐시 기능을 사용할 데이터 오브젝트 팩토리 목록을 기술해야 한다.
-
세션 캐시의 동작범위
세션 캐시는 한 트랜잭션 안에서 제공된다. 그러므로 일반적으로 서비스 단위로 제공되는 캐시로 생각하면 이해하기 쉽다. 다만 XA 트랜잭션이나 서비스 연동 호출의 경우 세션 캐시가 보장되지 않는 점을 주의한다.
-
세션 캐시의 동작방식
세션 캐시가 활성화된 경우 데이터 오브젝트 팩토리는 DO의 키 필드 값을 기준으로 세션 캐시에서 키에 해당하는 DO가 있는지 조회한다.
세션 캐시 저장소에 키에 해당하는 DO가 존재하면 데이터 오브젝트 팩토리는 사용자에게 키에 해당하는 DO를 반환한다. 키에 해당하는 DO가 없는 경우 쿼리를 실행하여 DB 데이터를 조회하여 DO를 생성하고, 사용자에게 반환하는 동시에 세션 캐시 저장소에 생성된 DO를 저장한다.
세션 캐시영역 시용하는 테이블들이 데이터 오브젝트 팩토리를 통해서 UPDATE/DELETE가 수행되면, 해당 세션 캐시들은 DIRTY 상태가 된다. 세션 캐시가 DIRTY가 되면, 데이터 오브젝트 팩토리는 세션 캐시에서 데이터를 조회하지 않고 DB 작업을 수행한다.
세션이 commit, rollback되는 경우 세션 캐시의 DIRTY 상태는 해제된다. 또한 commit을 수행하는 경우 세션 캐시가 DIRTY 상태라는 것은 세션 캐시가 바라보는 테이블들에 UPDATE, DELETE가 발생했다는 의미이므로 해당 테이블을 사용하는 세션 캐시 영역을 모두 무효화(invalidate)한다.
11.3. IProObjectCacheManager API
IProObjectCacheManager는 2차 캐시에 대한 접근을 위해 ProObject에서 제공하는 인터페이스 클래스다.
데이터 오브젝트 팩토리는 해당 인터페이스를 통해 캐시에 get, put, invalidate를 수행하므로 2차 캐시 제품을 데이터 오브젝트 팩토리에 적용하려면 IProObjectCacheManager를 구현한 구현체를 ProObject에 등록해야 한다.
TmaxSoft 제품인 InfiniCache와 연동을 하기 위해서는 IProObjectCacheMnager를 따로 구현할 필요 없이 system.properties의 SYSTEM_DATAOBJECT_SECOND_CACHE 값을 'com.tmax.proobject.dataobject.cache.InfiniCacheManager’로 입력하면 InfiniCache와 연동하여 캐시 기능을 데이터 오브젝트 팩토리에 적용할 수 있다.
사용자가 구현한 IProObjectCacheManager 객체는 ProObjectSecondCacheManager를 통해서만 접근할 수 있다. ProObjectSecondCacheManager는 IProObjectCacheManager의 API와 동일한 API를 제공하고 있으며, SYSTEM_DATAOBJECT_SECOND_CACHE에 지정한 IProObjectCacheManager의 구현체 클래스의 객체를 생성한다.
ProObjectSecondCacheManager를 사용하기 위해서는 다음과 같은 방법으로 객체를 얻어 온 후 API를 통해 데이터 조회나 업데이트, 추가, 삭제할 수 있다.
com.tmax.proobject.dataobject.cache.ProObjectSecondCacheManager manager = ProObjectSecondCacheManager.getInstance();
11.3.1. get
캐시에서 데이터를 조회하기 위해 사용한다.
다음은 API 사용법에 대한 설명이다.
-
사용법
public <T> T get(String cacheName, Object key)
파라미터 설명 String cache Name
조회하려는 데이터 오브젝트 이름이다.
Object key
캐시에서 데이터를 찾기 위한 키 값이다.
11.3.2. put
캐시에 데이터를 추가하기 위해 사용한다.
다음은 API 사용법에 대한 설명이다.
-
사용법
public <T> void put(String cacheName, Object key, T item)
파라미터 설명 String cache Name
추가하려는 데이터 오브젝트 이름이다.
Object key
조회를 하기 위한 캐시의 키 값이다.
T item
추가하려는 데이터 오브젝트이다.
11.3.3. invalidate
입력 받은 데이터 오브젝트 명에 해당하는 모든 데이터 오브젝트를 캐시에서 초기화한다.
다음은 API 사용법에 대한 설명이다.
-
사용법
public void invalidate(String cacheName)
파라미터 설명 String cacheName
초기화하려는 데이터 오브젝트 이름이다.