전자정부표준프레임워크 Data Access Service 소개 2011-02-23 오픈커뮤니티김영우커미터
< 목차 > 1. Data Access Service 개요 (ibatis 활용 ) 3. DBIO 소개
Contents 1. Data Access Service 개요 1-1. 데이터처리레이어란? 1-2. 데이터처리레이어구성요소 1-3. Data Access Service 기술 1-4. ibatis 소개 1-5. ibatis 개요
1-1. 데이터처리레이어란? (1/2) 1. Data Access Service 개요 데이터베이스에대한연결및영속성처리, 선언적인트랜잭션관리를제공하는 Layer 전자정부개발프레임워크실행환경 서비스그룹 Presentation Layer 설명 업무프로그램과사용자간의 Interface 를담당하는 Layer 로서, 사용자화면구성, 사용자입력정보검증등의기능을제공함 Layer Presentation Layer Business Logic Layer Persistence Layer Integration Business Logic Layer 업무프로그램의업무로직을담당하는 Layer 로서, 업무흐름제어, 에러처리등의기능을제공함 Persistence Layer 데이터베이스에대한연결및영속성처리, 선언적인트랜잭션관리를제공하는 Layer 임 Foundation Layer ( 공통기반레이어 ) Integration Layer 타시스템과의연동기능을제공하는 Layer 임 환경 서비스그룹 Foundation Layer ( 공통기반레이어 ) 실행환경의각 Layer 에서공통적으로사용하는공통기능을제공함 4
1-1. 데이터처리레이어란? (2/2) 1. Data Access Service 개요 데이터처리레이어는 DataSource, Data Access 등총 4 개의서비스를제공함 실행환경 화면처리레이어 업무처리레이어 데이터처리레이어 연계통합레이어 MVC Internationalization Process Control Data Source Data Access Naming Service Ajax Support Security Exception Handling ORM TBD Transaction Integration Service UI Adaptor Web Service 공통기반레이어 AOP Cache Compress /Decompress Encryption /Decryption Excel File Handling File Upload /Download FTP Server Security ID Generation IoC Container Logging Mail Marshalling /Unmarshalling Object Pooling Property Resource Scheduling String Util XML Manipulation 실행환경서비스그룹서비스 5
1-2. 데이터처리레이어구성요소 1. Data Access Service 개요 데이터처리레이어는 Spring MVC, ibatis 등총 4 종의오픈소스 SW를사용하고있음 서비스 오픈소스 SW 버전 DataSource Spring 2.5 Data Access ibatis SQL Maps 2.3 ORM Hibernate 3.2 Transaction Spring 2.5 6
1-3. Data Access Service 기술 ORM(1/2) 1. Data Access Service 개요 ORM(Object Relational Mapping) 은데이터베이스연계처리를위하여기존의 SQL 에의존하는것이아니라, 직접테이블의컬럼을자바 Class 에매핑하거나 XML 형태의 SQL 을실행하여처리를수행하는것을말함 SQL과소스의혼재 SQL 소스의혼재 Business Logic Business Logic SQL과소스의분리 SQL 소스의분리 Full Full ORM ORM (Hibernate) (Hibernate) DB Column Java Class Mapping SQL JDBC Partial Partial ORM ORM (ibatis) (ibatis) JDBC Java-Mapping DataBase Business Logic SQL MAP (SQL 을 XML 로처리 ) DataBase 순수한객체지향프로그래밍에의한데이터처리 DB 의 SQL 에의한종속성탈피 (DB 교체등의변경에대한유연성 ) DB 와프로그램변수에대한관계성을미리정의함 (Mapping) 7
1-3. Data Access Service 기술 ORM(2/2) SQL Map 구현코드사례 1. Data Access Service 개요 SQL과소스의혼재 SQL 소스의혼재 SQL과소스의분리 SQL 소스의분리 Statement st = null; ResultSet rs = null; try { st = con.createstatement(); StringBuffer query = new StringBuffer(); query.append("\n SELECT A.CHKLST_NO, "); query.append("\n A.EVALFL_CD, "); query.append("\n FROM PR_EVALIT_MB A "); query.append("\n WHERE A.CHKLST_NO = '" + schklstno + "' "); query.append("\n ORDER BY EVALIT_NO rs = st.executequery(st.tostring()); while(rs.next) {... } } finally { try {rs.close();} catch (Exception e) {} try {st.close();} catch (Exception e) {} } 업무로직과업무로직과 SQL분리 SQL분리 // Component List result = ISqlManagement.getList( sql.id, value ) // SqlMap.xml <select id= id resultclass = hmap > SELECT A.CHKLST_NO, A.EVALFL_CD FROM PR_EVALIT_MB A WHERE A.CHKLST_NO = #value# ORDER BY EVALIT_NO </select> 8
1-4. ibatis 소개 ibatis 는단순성이라는사상을강조한퍼시스턴스프레임워크로, SQL 맵을이용하여반복적이고복잡한 DB 작업코드를최소화함 - 단순성이라는사상을강조하여, XML 을이용하여 Stored Procedure 혹은 SQL 문과자바객체간의매핑을지원 - 2001 년 Clinton Begin (Apache 소프트웨어재단 ) 에의해 개발된퍼시스턴스프레임워크 * Performance Comparison of Persistence Frameworks, Sabu M. Thampi, Ashwin a K. (2007) 9
1-5. ibatis 개요 (1/3) 전자정부표준프레임워크에서는 JDBC 를사용한 Data Access 를추상화하여간편하고쉽게사용할수있는 Data Mapper framework 인 ibatis 를 Data Access 기능의기반오픈소스로채택 ibatis 를사용하면관계형데이터베이스에엑세스하기위해필요한일련의자바코드사용을현저히줄일수있으며간단한 XML 기술을사용하여 SQL 문을 JavaBeans ( 또는 Map) 에간편하게매핑할수있음 Data Access 서비스는다양한데이터베이스솔루션및데이터베이스접근기술에일관된방식으로대응하기위한서비스 10
1-5. ibatis 개요 (2/3) ibatis 주요기능 - 추상화된접근방식제공 JDBC 데이터억세스에대한추상화된접근방식으로간편하고쉬운 API, 자원연결 / 해제, 공통에러처리등을통합지원함 - 코드로부터 SQL 분리지원 소스코드로부터 SQL 문을분리하여별도의 repository( 의미있는문법의 XML) 에유지하고이에대한빠른참조구조를내부적으로구현하여관리 / 유지보수 / 튜닝의용이성을보장함 - 쿼리실행의입 / 출력객체바인딩 / 맵핑지원 쿼리문의입력파라메터에대한바인딩과실행결과 resultset 의가공 ( 맵핑 ) 처리시객체 (VO, Map, List) 수준의자동화를지원함 - Dynamic SQL 지원 코드작성, API 직접사용없이입력조건에따른동적인쿼리문변경을지원함 - 다양한 DBMS 기능지원 기본질의외에 Batch SQL, Paging, Callable Statement, BLOB/CLOB 등다양한 DB처리를지원함 11
1-5. ibatis 개요 (3/3) Data Access 서비스 - ibatis Data Mapper API 는 XML 을사용하여 SQL 문에대한객체맵핑을간편하게기술할수있도록지원 - 자바빈즈객체와 Map 구현체, 다양한원시래퍼타입 (String, Integer..) 등을 PreparedStatement 의파라메터나 ResultSet 에대한결과객체로쉽게맵핑해줌 12
2-1. ibatis Configuration 2-2. Mapped Statement 2-3. Data Type 2-4. parametermap 2-5. Inline parameters 2-6. resultmap 2-7. Dynamic SQL 2-8. 표준프레임워크 Data Access Service
2-1. ibatis Configuration(1/3) sql-map-config.xml SqlMapClient 설정관련상세내역을제어할수있는메인설정파일로주로 transaction 관리관련설정및다양한옵션설정 Sql Mapping 파일들에대한 path 설정등을포함 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sqlmapconfig PUBLIC "-//ibatis.com//dtd SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> <sqlmapconfig> <properties resource="meta-inf/spring/jdbc.properties" /> <settings cachemodelsenabled="true" enhancementenabled="true" lazyloadingenabled="true" maxrequests="128" maxsessions="10" maxtransactions="5" usestatementnamespaces="false" defaultstatementtimeout="1" /> <typehandler javatype="java.util.calendar" jdbctype="timestamp" callback="egovframework.rte.psl.dataaccess.typehandler.calendartypehandler" /> <transactionmanager type="jdbc"> <datasource type="dbcp"> <property name="driverclassname" value="${driver}" /> <property name="url" value="${dburl}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <!-- OPTIONAL PROPERTIES BELOW --> 14
2-1. ibatis Configuration(2/3) sql-map-config.xml <property name="maxactive" value="10" /> <property name="maxidle" value="5" /> <property name="maxwait" value="60000" /> <!-- validation query --> <!--<property name="validationquery" value="select * from DUAL" />--> <property name="logabandoned" value="false" /> <property name="removeabandoned" value="false" /> <property name="removeabandonedtimeout" value="50000" /> <property name="driver.driverspecificproperty" value="somevalue" /> </datasource> </transactionmanager> <sqlmap resource="meta-inf/sqlmap/mappings/testcase-basic.xml" /> <sqlmap../>.. </sqlmapconfig> 15
2-1. ibatis Configuration(3/3) SQL Map XML 파일 (sql 매핑파일 ) <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sqlmap PUBLIC "-//ibatis.com//dtd SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd"> <sqlmap namespace="dept"> <typealias alias="deptvo" type="egovframework.deptvo" /> <resultmap id="deptresult" class="deptvo"> <result property="deptno" column="dept_no" /> <result property="deptname" column="dept_name" /> <result property="loc" column="loc" /> </resultmap> <insert id="insertdept" parameterclass="deptvo"> insert into DEPT (DEPT_NO, DEPT_NAME, LOC) values (#deptno#, #deptname#, #loc#) </insert> <select id="selectdept" parameterclass="deptvo" resultmap="deptresult"> <![CDATA[ ]]> </select> </sqlmap> select from where DEPT_NO, DEPT_NAME, LOC DEPT DEPT_NO = #deptno# 16
2-2. Mapped Statement Data Mapper 사상의핵심으로 Mapped Statement 는 parameter 매핑 (input) 과 result 매핑 (output) 을가질수있는어떤 SQL 문이라도될수있다. 단순하게는파라메터나결과에대한 class 를직접적으로설정할수있으며 ( 권고하지않는방법이지만아예설정하지않고프레임워크에서제공하는자동맵핑처리도가능 ), in/out 매핑, 결과의 cache 유지등에대한상세한설정이가능하다. statement 구문 <statement id="statementname" [parameterclass="some.class.name"] [resultclass="some.class.name"] [parametermap="nameofparametermap"] [resultmap="nameofresultmap"] [cachemodel="nameofcache"] [timeout="5"]> select * from PRODUCT where PRD_ID = [? #propertyname#] order by [$simpledynamic$] </statement> 17
2-3. Data Type 어플리케이션을작성할때 Data Type 에대한올바른사용과관련처리는매우중요함 데이터베이스를이용하여데이터를저장하고조회할때 Java 어플리케이션에서의 Type 과 DBMS 에서지원하는관련매핑 jdbc Type 의정확한사용이필요함 18
2-4. parametermap 해당요소로 SQL 문외부에정의한입력객체의속성에대한 name 및 javatype, jdbctype 을비롯한옵션을설정할수있는매핑요소임 JavaBeans 객체 ( 또는 Map 등 ) 에대한 prepared statement 에대한바인드변수매핑을처리할수있음 유사한기능을처리하는 parameterclass 나 Inline Parameter 에비해많이사용되지않지만더기술적인 (descriptive) parametermap( 예를들어 stored procedure 를위한 ) 이필요함 XML 의일관된사용과순수성을지키고자할때좋은접근법이될수도있음 Dynamic 요소와함께사용될수없고바인드변수의갯수와순서를정확히맞춰야하는불편이있는등일반적으로사용을추천하지않음 19
2-4. parametermap parametermap Sample.. <typealias alias="empvo" type="egovframework.rte.psl.dataaccess.vo.empvo" /> <parametermap id="empparam" class="empvo"> <parameter property="empno" javatype="decimal" jdbctype="numeric" /> <parameter property="empname" javatype="string" jdbctype="varchar" nullvalue="blank" /> <parameter property="job" javatype="string" jdbctype="varchar" nullvalue="" /> <parameter property="mgr" javatype="decimal" jdbctype="numeric" /> <parameter property="hiredate" javatype="date" jdbctype="date" /> <parameter property="sal" javatype="decimal" jdbctype="numeric" /> <parameter property="comm" javatype="decimal" jdbctype="numeric" nullvalue="-99999" />\ <parameter property="deptno" javatype="decimal" jdbctype="numeric" / </parametermap> <insert id="insertempusingparametermap" parametermap="empparam"> <![CDATA[ insert into EMP (EMP_NO, EMP_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO) values (?,?,?,?,?,?,?,?) ]]> </insert> 20
2-5. Inline Parameters prepared statement 에대한바인드변수매핑처리를위한 parametermap 요소 SQL 문외부에정의한입력객체 property name 및 javatype, jdbctype 을비롯한옵션을설정매핑요소와동일한기능을처리하는간편한방법을 Inline Parameters 방법으로제공보통 parameterclass 로명시된입력객체에대해바인드변수영역을간단한 #property# 노테이션으로나타내는 Inline Parameter 방법은기존 parametermap 에서의? 와이의순서를맞춘외부 parametermap 선언으로처리하는방법에비해많이사용되고일반적으로추천하는방법 Dynamic 요소와함께사용될수있고별도의외부매핑정의없이바인드변수처리가필요한위치에해당 property 를직접사용가능하며, 필요한경우 jdbctype 이나 nullvalue 를간단한추가노테이션과같이지정할수있음 21
2-5. Inline Parameters Inline Parameters Sample.. <typealias alias="empvo" type="egovframework.rte.psl.dataaccess.vo.empvo" /> <insert id="insertemptusinginlineparam"> <![CDATA[ insert into EMP (EMP_NO, ]]> </insert> EMP_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO) values (#empno:numeric#, #emname:varchar:blank#, #job:varchar:""#, /* inline parameter 에서는 empty String 을 nullvalue 로대체할수없음 - cf.) oracle 인경우는 "" 가 null 임 */ #mgr:numeric#, #hiredate:date#, #sal:numeric#, #comm,javatype=decimal,jdbctype=numeric,nullvalue=-99999#, #deptno:numeric#) 22
2-6. resultmap resultmap 은 SQL 문외부에정의한매핑요소 result set 으로부터어떻게데이터를뽑아낼지, 어떤칼럼을어떤 property 로매핑할지에대한상세한제어를가능케해줌 resultmap 은일반적으로가장많이사용되는중요한매핑요소로 resultclass 속성을이용한자동매핑접근법에비교하여칼럼타입의지시, null value 대체값, typehandler 처리, complex property 매핑 ( 다른 JavaBean, Collections 등을포함하는복합객체 ) 등을허용함 23
2-6. resultmap resultmap Structure - resultmap 태그의 extends 속성을명시하면외부에정의한다른 resultmap 을상속 ( 관련 property - column 매핑을현재 resultmap 에정의하지않고도 ) 할수있으며, groupby 속성을사용하여 nested resultmap 에서의 N+1 쿼리문제를풀수있도록해당속성을통해명시한 property 리스트의값이같은 row 들에대해하나의결과객체로생성해주게된다. <resultmap id="resultmapname" class="some.domain.class" [extends="parent-resultmap"] [groupby="some property list"]> <result property="propertyname" column="column_name" [columnindex="1"] [javatype="int"] [jdbctype="numeric"] [nullvalue="-999999"] [select="someotherstatement"] [resultmap="someotherresultmap"] [typehandler="com.mydomain.mytypehandler"] /> <result /> <result /> <result /> </resultmap> 24
2-6. resultmap Sample resultmap.. <typealias alias="empvo" type="egovframework.rte.psl.dataaccess.vo.empvo" /> <resultmap id="empresult" class="empvo" > <result property="empno" column="emp_no" columnindex="1" javatype="decimal" jdbctype="numeric" /> <result property="empname" column="emp_name" columnindex="2" javatype="string" jdbctype="varchar" /> <result property="job" column="job" columnindex="3" javatype="string" jdbctype="varchar" /> <result property="mgr" column="mgr" columnindex="4" javatype="decimal" jdbctype="numeric" /> <result property="hiredate" column="hire_date" columnindex="5" javatype="date" jdbctype="date" /> <result property="sal" column="sal" columnindex="6" javatype="decimal" jdbctype="numeric" /> <result property="comm" column="comm" columnindex="7" javatype="decimal" jdbctype="numeric" nullvalue="0" /> <result property="deptno" column="dept_no" columnindex="8" javatype="decimal" jdbctype="numeric" /> </resultmap> <select id="selectempusingresultmap" parameterclass="empvo" resultmap="empresult"> <![CDATA[ select EMP_NO, EMP_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO from EMP where EMP_NO = #empno# ]]> </select> 25
2-7. Dynamic SQL 일반적으로 JDBC API 를사용한코딩에서한번정의한쿼리문을최대한재사용하고자하나단순파라메터변수의값만변경하는것으로해결하기어렵고다양한조건에따라조금씩다른쿼리의실행이필요한경우많은 if~else 조건분기의연결이필요한문제가있음 Dynamic SQL mapping xml 파일.. <typealias alias="jobhistvo" type="egovframework.rte.psl.dataaccess.vo.jobhistvo" /> <select id="selectjobhistlistusingdynamicelement" parameterclass="jobhistvo" resultclass="jobhistvo"> <![CDATA[ select EMP_NO as empno, START_DATE as startdate, END_DATE as enddate, JOB as job, SAL as sal, COMM as comm, DEPT_NO as deptno from JOBHIST ]]> <dynamic prepend="where"> <isnotnull property="empno" prepend="and"> EMP_NO = #empno# </isnotnull> </dynamic> order by EMP_NO, START_DATE </select> 26
2-7. Dynamic SQL Dynamic SQL - Unary 비교연산 Sample Unary 비교연산.. <typealias alias="egovmap" type="egovframework.rte.psl.dataaccess.util.egovmap" /> <select id="selectdynamicunary" parameterclass="map" remapresults="true" resultclass="egovmap"> select <dynamic> <isempty property="testemptystring">.. </dynamic> </select> 'empty String' as IS_EMPTY_STRING </isempty> <isnotempty property="testemptystring"> 'not empty String' as IS_EMPTY_STRING </isnotempty> <ispropertyavailable prepend=", " property="testproperty"> 'testproperty Available' astest_property_available </ispropertyavailable> <isnotpropertyavailable prepend=", " property="testproperty"> 'testproperty Not Available' as TEST_PROPERTY_AVAILABLE </isnotpropertyavailable> from dual 27
2-7. Dynamic SQL Binary 비교연산 Sample Binary 비교연산.. <typealias alias="egovmap" type="egovframework.rte.psl.dataaccess.util.egovmap" /> <select id="selectdynamicbinary" parameterclass="map" remapresults="true" resultclass="egovmap"> select <dynamic> <isequal property="teststring" comparevalue="test"> '$teststring$' as TEST_STRING, 'test : equals' as IS_EQUAL </isequal> <isnotequal property="teststring" comparevalue="test"> '$teststring$' as TEST_STRING, 'test : not equals' as IS_EQUAL </isnotequal>.. <islessthan property="testotherstring" prepend=", " compareproperty="teststring"> '''$testotherstring$'' <![CDATA[<]]> ''$teststring$''' as COMPARE_PROPERTY_LESS_THAN </islessthan> </ispropertyavailable> </dynamic> from dual </select>.. 28
2-7. Dynamic SQL ParameterPresent 비교 Sample ParameterPresent 비교.. <typealias alias="egovmap" type="egovframework.rte.psl.dataaccess.util.egovmap" /> <select id="selectdynamicparameterpresent" parameterclass="map" remapresults="true" resultclass="egovmap"> select <isparameterpresent> 'parameter object exist' as IS_PARAMETER_PRESENT </isparameterpresent> <isnotparameterpresent> 'parameter object not exist' as IS_PARAMETER_PRESENT </isnotparameterpresent> from dual </select> 29
2-7. Dynamic SQL iterate 연산 Sample iterate 연산 <typealias alias="jobhistvo" type="egovframework.rte.psl.dataaccess.vo.jobhistvo" /> <typealias alias="empincludesemplistvo" type="egovframework.rte.psl.dataaccess.vo.empincludesemplistvo" /> <select id="selectjobhistlistusingdynamiciterate" parameterclass="empincludesemplistvo" resultclass="jobhistvo"> <![CDATA[ select EMP_NO as empno, START_DATE as startdate, END_DATE as enddate, JOB as job, SAL as sal, COMM as comm, DEPT_NO as deptno from JOBHIST ]]> <dynamic prepend="where"> <iterate property="emplist" open="emp_no in (" conjunction=", " close=")"> #emplist[].empno# </iterate> </dynamic> order by EMP_NO, START_DATE </select> 30
2-8. 표준프레임워크 Data Access Service 전자정부표준프레임워크 Data Access 구조 Client Service EgovAbstractDAO extends Controller ServiceImpl xxxdao insert() update() delete() selectbypk() list() 31
2-8. 표준프레임워크 Data Access Service EgovAbstractDAO 의역할 - Spring 의 ibatis 연동지원을 Annotation 형식으로쉽게처리 - Spring 에서 ibatis 연동을지원하는 org.springframework.orm.ibatis.support.sqlmapclientdaosupport 을 extends - CRUD 와관련한대표적인 method 를간단하게호출할수있도록 Wrapping - 사용자 DAO 에서 ibatis sqlmapclient 쉽게호출 - Annotation 기반으로 sqlmapclient 를쉽게 Injection 하는로직을포함 32
2-8. 표준프레임워크 Data Access Service EgovMap 의역할 - Camel Case 표기법변환처리를포함하는 Map 확장클래스 - commons Collections 의 ListOrderedMap 을 extends 하고있으며 Map 의 key 를입력시 Camel Case 표기법으로 변경하여처리하는 Map 의구현체 - ibatis 의경우 egovmap 으로결과조회시별도의 alias 없이 DB 칼럼명그대로조회하는것만으로도일반적인 VO 의 attribute (camel case) 에대한 resultmap 과같은효과를낼수있음 33
향후검토사항 Data access Service 개선방안 Ibatis3.0의적용 JDBC template의적용 Hibernate 적용 기존프레임워크와의상호변환가이드제공 34