목차 >> Data Access Object(DAO)  
+- GlueGenericDao  
+- GlueJdbcDao  
+- GlueMyBatisDao  
+- GlueHibernateDao  
----+- hbm.xml  
----+- Glue Query File(HQL)  
----+- GlueHiberanteParameter  
----+- Reuse Activity

6장 Data Access Object(DAO)

GlueHibernateDao

GlueHibernateDao는 Hibernate를 이용해서 추상화된 CRUD 오퍼레이션을 사용할 수 있는 Database Access Object 구현체입니다. GlueHiberanteDao는 GlueGenericHibernateDao인터페이스를 구현하였으며, GlueHibernateDao의 상속관계 및 메소드는 Java Doc을 참고합니다. (GlueAPI)

GlueHibernateDao 의 필수 속성(property)는 다음과 같습니다.

  • sessionFactory : 참조할 SessionFactory Bean
  • queryManager : 참조할 QueryManager Bean (Query Manager 참고).
    그림 : GlueGenericHibernateDao
    GlueGenericHibernateDao

    본 가이드에서는 Glue와 Hibernate 연계 관련된 기본적인 내용에 대해서만 다룰 것이므로, Hibernate에 대한 자세한 내용은 Hibernate 공식 사이트의 매뉴얼을 참고하기 바랍니다.
    영문 사이트

    그림 : GlueHibernateDao의 bean들과의 관계
    GlueHibernateDao의 bean들과의 관계

    GlueHibernateDao를 사용하기 위해서는 applicationContext.xml에 SessionFactory, QueryManager가 등록되어 있어야 합니다.
    다음은 설정파일(applicationContext.xml)의 일부입니다.

    <bean id="dao-1" class="com.poscoict.glueframework.dao.hibernate.GlueHibernateDao">
        <property name="sessionFactory" ref="sessionFactory-1"/>
        <property name="queryManager" ref="queryManager"/>
    </bean>
    <bean id="sessionFactory-1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref=" dataSource-1"/>
        <property name="mappingResources">
            <list>
                <value>HbSample01.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.transaction.flush_before_completion">false</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource-1" class= . . ./>
    
    <bean id="dao-2" class="com.poscoict.glueframework.dao.hibernate.GlueHibernateDao">
        <property name="sessionFactory" ref="sessionFactory-2"/>
        <property name="queryManager" ref="queryManager"/>
    </bean>
    <bean id="sessionFactory-2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref=" dataSource-2"/>
        <property name="mappingResources">
            <list>
                <value>Sample01.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.transaction.flush_before_completion">false</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource-2" class= . . ./>
    
    <bean id="transactionManager-1" class="com.poscoict.glueframework.transaction.GlueHibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory-1"/>
    </bean>
    <bean id="transactionManager-2" class="com.poscoict.glueframework.transaction.GlueHibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory-2"/>
    </bean>
    
    <bean id="queryManager" class="com.poscoict.glueframework.dao.manager.GlueQueryManagerImpl">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="queryLoader" ref="queryLoader"/>
    </bean>
    <bean id="cacheManager" class= . . . />
    <bean id="queryLoader" class= . . . />
    

    dao-1은 Hibernate용 DAO bean으로 SessionFactory와 QueryManager를 필요로 합니다. SessionFactory에 해당하는 sessionFactory-1은 Hibernate Session관리 객체로 Hibernate 관련 설정 정보를 셋업합니다.
    sessionFactory-1의 mappingResources property에는 hbm.xml 을 설정하며, Database와 연동되는 Value Object 정보가 포함되어 있습니다.
    sessionFactory-1의 hibernateProperties property에는 Hibernate 정책 및 세부 설정 사항을 지정한합니다. 설정사항은 Hibernate 공식 사이트를 참고하기 바랍니다.

hbm.xml

Hibernate ORM 매핑방식 중 hbm.xml 매핑 설정 방식이 있습니다. hbm.xml에 Database Schema를 정의하고 Hibernate의 설정을 지정하는 파일입니다. Hibernate 사용방법에 대해 정확한 습득을 필요로 하면 Hibernate 공식 사이트를 참고하시기 바랍니다.
다음은 hbm.xml 예제입니다.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="sample.vo.Employee" table="Emp" dynamic-update="true">
        <id name="empno" column="EMPNO">
            <generator class="increment"/>
        </id>
        <property name="ename" column="ENAME" type="string"/>
        <property name="job" column="JOB" type="string"/>
        <property name="mgr" column="MGR" type="big_decimal"/>
        <property name="hiredate" column="HIREDATE" type="timestamp"/>
        <property name="sal" column="SAL" type="big_decimal"/>
        <property name="comm" column="COMM" type="big_decimal"/>
        <property name="deptno" column="DEPTNO" type="big_decimal"/>
    </class>
</hibernate-mapping>

위와 같은 작성된 hbm.xml을 살펴보면, class 요소의 name을 통해 Value Object Class가 지정되어 있고, Entity를 구분하기 위한 id 가 있고, 그외 property들을 볼 수 있습니다. Id는 increment generator를 사용하고 있습니다.
Value Object는 DB 컬럼에 해당하는 멤버 변수와 Setter / Getter Method를 갖습니다. 상황에 따라 Business Logic이 들어갈 수 있으며 Hibernate 관련 Annotation을 사용할 수 있습니다.
다음은 sample.vo.Employee 예제입니다. hbm.xml의 id로 지정된 empno는 increment generator를 사용하도록 하였기 때문에 long, short과 같은 타입만 허용됩니다. 만약 다른 Type을 사용하려면 generator를 직접 개발해야 합니다.

package sample.vo;
import java.math.BigDecimal;
import java.sql.Timestamp;
public class Employee {
    // bhm.xml에서 increment generator를 사용하려면 long형을 사용해야 한다.
    private long empno;
    private String ename;
    private String job;
    private BigDecimal mgr;
    private Timestamp hiredate;
    private BigDecimal sal;
    private BigDecimal comm;
    private BigDecimal deptno;
    public Employee( long empno ) {
        this.empno = empno;
    }
    public long getEmpno() {
        return empno;
    }
    public void setEmpno( long empno ) {
        this.empno = empno;
    }
    public String getEname() {
        return ename;
    }
    public void setEname( String ename ) {
        this.ename = ename;
    }
    public String getJob() {
        return job;
    }
    public void setJob( String job ) {
        this.job = job;
    }
    public BigDecimal getMgr() {
        return mgr;
    }
    public void setMgr( BigDecimal mgr ) {
        this.mgr = mgr;
    }
    public Timestamp getHiredate() {
        return hiredate;
    }
    public void setHiredate( Timestamp hiredate ) {
        this.hiredate = hiredate;
    }
    public BigDecimal getSal() {
        return sal;
    }
    public void setSal( BigDecimal sal ) {
        this.sal = sal;
    }
    public BigDecimal getComm() {
        return comm;
    }
    public void setComm( BigDecimal comm ) {
        this.comm = comm;
    }
    public BigDecimal getDeptno() {
        return deptno;
    }
    public void setDeptno( BigDecimal deptno ) {
        this.deptno = deptno;
    }
}

다음은 EMP table 생성 Script 예제입니다. 아래 예제는 Oracle용 EMP 생성 Script 입니다.

CREATE TABLE EMP 
(
    EMPNO      NUMBER (4) NOT NULL,
    ENAME      VARCHAR2 (10),
    JOB        VARCHAR2 (9),
    MGR        NUMBER (4),
    HIREDATE   DATE,
    SAL        NUMBER (7,2),
    COMM       NUMBER (7,2),
    DEPTNO     NUMBER (2),
    CONSTRAINT FK_DEPTNO FOREIGN KEY (DEPTNO) REFERENCES DEPT (DEPTNO)
)

Glue Query File(HQL)

O/R 맵핑 툴의 하나인 Hibernate 는 HQL 에 의한 질의를 수행합니다. HQL 이란 Hibernate Query Language 의 약어로 Hibernate를 통해 데이터베이스를 검샐할 경우에 이용하는 쿼리입니다. HQL 을 Hibernate가 어떤 데이터베이스를 이용하고 있는지 살펴보고 알아서 그에 맞는 SQL 로 변환하여 준다는 장점이 있습니다. HQL 은 SQL 에 비슷하지만 클래스의 프로퍼티를 쓴다는 점이 특징입니다.
Glue Query File 작성시 JDBC용 Query와 Hibernate HQL를 구분하기 위해 [-hquery.glue_sql]과 같이 Query File명을 다르게 지정합니다. 작성되는 HQL은 named query형태로만 작성합니다. 즉, isNamed 속성을 true로 합니다. Hibernate를 사용하기 위해서는 일반적인 DB 벤더에서 사용하는 SQL과 상이한 HQL 언어에 대해서 알고 있어야 합니다. 다음은 hbm.xml에서 예제로 사용한 EMP 테이블을 매핑한 Employee 를 대상으로 한 HQL로 작성된 Glue Query File 일부입니다.

<?xml version="1.0" encoding="UTF-8"?>
<queryMap desc="Employee Query for Hibernate" xmlns="http://www.poscoict.com/glueframework/query">
    <query id="Employee.find" desc="find employee by empno" isNamed="true">
        <![CDATA[ 
from Employee e where e.empno = :empno order by e.empno asc
        ]]> 
    </query>
    <query id="Employee.findByDept" desc="find employee by detpno" isNamed="true">
        <![CDATA[ 
from Employee e where e.deptno = :deptno order by e.empno asc
        ]]> 
    </query>
    <query id="Employee.update" desc="find employee by detpno" isNamed="true">
        <![CDATA[ 
update Employee set comm = :comm where empno = :empno
        ]]> 
    </query>
    <query id="Employee.delete" desc="find employee by detpno" isNamed="true">
        <![CDATA[ 
delete Employee where empno = :empno
        ]]> 
    </query>
</queryMap>

Employee.find라는 query id로 부여된 HQL은 Emp Table에서 binding한 deptno와 동일한 사원을 조회하여 Employee 객체의 List를 Return하는 쿼리입니다. from 뒤의 Employee 는 DB Table 명이 아닌 Hibernate의 Entity 명임에 주의합니다. HQL에서는 named query와 ? 방식의 query도 지원하나, Glue Framework의 Reusable Activity는 named Query만 지원하고 있습니다.
Employee.update라는 query id로 부여된 HQL은 Emp Table에서 binding한 사원번호의 Comm 컬럼을 Update하는 쿼리입니다.
Employee.delete라는 query id로 부여된 HQL은 Emp Table에서 사원번호로 Delete하는 쿼리입니다.
Hibernate에서 Insert 쿼리는 제한적으로 지원하나, Glue Framework에서는 제공하는 Resue Activity에는 insert 쿼리를 위한 것은 없습니다. Hibernate에서 제한적으로 insert HQL이 지원되기에 Glue Framework에서는 Entity 기반의 Reuse Activity를 이용하기를 권고합니다.
Hibernate에서는 HQL을 통해 기본적인 Insert, Update, Delete 구문을 지원하지만, GlueHibernateDao를 통해 사용하지 않을 것을 권고합니다. Hiberante를 이용하여 Data를 조회한 후 Custom Activity등에서 각Value Object에 접근하여 Business Data를 변경한 후 Commit을 통해 Database에 변경된 내용을 적용하는 방식으로 개발하기 바랍니다. insert/update/delete HQL의 사용은 Hibernate의 OR mapping 사상과 맞지 않는 개념이기 때문입니다. Value Object을 통한 CRUD가 아닌 경우는 GlueJdbcDao/GlueMyBatisDao의 Data 수정/등록/삭제 기능을 활용 할 수 있습니다.
아래는 Hibernate VO에 Update하는 Sample Code입니다.

public class SampleActivity extends GlueActivity<GlueContext> {
    @Override
    public String runActivity(GlueContext ctx) {
        GlueGenericHibernateDao dao = . . .;
        GlueParameter param = . . .;
        List<Employee> rowSet = dao.find("Employee.findByDept", param);
        for ( Employee emp : voList ) {
            //  Logic을 작성한다
            if( isUpdateEmployee(emp) ) {
                emp.setComm(new BigDecimal("1"));
            }
        }
        // 필요시 commit/rollback을 activity layer에서 처리 가능함.
        // this.commitTransaction( "transactionManager-1" );
        // this.rollbackTransaction( "transactionManager-1" );
        return GlueBizControlConstants.SUCCESS;
    }
    private boolean isUpdateEmployee(Employee emp){
        . . . . 
    }
}

GlueHiberanteParameter

GlueHibernateDao를 이용한 HQL based/Entity Based method 실행시 GlueParameter를 필요로 합니다. HQL은 Named Query만을 사용할 수 있으므로, GlueParameter는 Map으로 구성합니다. 구성된 Map 객체는 setParameter() 를 이용하거나, 생성자를 이용합니다.
GlueHiberanteParameter는 entityName 과 bindingNamings 를 추가로 갖고 있습니다. entitiyName는 update()/delete()/createEntity()/modifyEntity() 메소드 사용시 date의 TypeCasting에 사용됩니다. bindingNamings는 find()/update()/delete() 와 createEntity()/modifyEntity() 메소드 사용시 entity의 Field명과 dataMap의 key가 일치하지 않을 경우 사용됩니다.
다음은 find() 메소드를 사용할 경우 GlueParameter를 구성하는 예입니다.

Map<String, String> dataMap = new HashMap<String, String>();
dataMap.put( "deptno", "40" );
GlueParameter param = new GlueHibernateParameter<Map<String, String>>( dataMap );
List<?> rowSet = dao.find( "Employee.findByDept", param );

다음은 named param 이 같지 않을 경우 GlueParameter를 구성하는 예입니다.

// from Employee e where e.deptno = :deptno1 order by e.empno asc
Map<String, String> dataMap = new HashMap<String, String>();
dataMap.put( "deptno1", "40" );
Map<String, String> bindings = new HashMap<String, String>();
bindings.put( "deptno1", "deptno" );

GlueParameter param = new GlueHibernateParameter<Map<String, String>>();
param.setParameter( dataMap );
( (GlueHibernateParameter<?>) param ).setBindingNamings( bindings );

List<?> rowSet = dao.find( "Employee.findByDept.2", param );

다음은 update/delete() 메소드를 사용할 경우 GlueParamter를 구성하는 예입니다.

Map<String, String> dataMap = new HashMap<String, String>();
dataMap.put( "empno", "1111" );
dataMap.put( "comm", "3333" );

GlueParameter param = new GlueHibernateParameter<Map<String, String>>( dataMap );
( (GlueHibernateParameter<?>) param ).setEntityName( "sample.vo.Employee" );

int cnt = dao.update( "Employee.update", param );

다음은 createEntity()/modifyEntity() 메소드를 사용할 경우 GlueParameter를 구성하는 예입니다.

Map<String, String> dataMap = new HashMap<String, String>();
dataMap.put( "empno", "4111" );
dataMap.put( "ename", "Test1" );
dataMap.put( "deptno", "40" );

GlueParameter param = new GlueHibernateParameter<Map<String, String>>( dataMap );
( (GlueHibernateParameter<?>) param ).setEntityName( "sample.vo.Employee" );

Object obj = dao.createEntity( "sample.vo.Employee", param );

Reuse Activity

GlueHibernateDao를 사용한 reuse Activity는 다음과 같은 것이 제공되고 있습니다.

  • com.poscoict.glueframework.biz.activity.hibernate.GlueHibernateDelete
  • com.poscoict.glueframework.biz.activity.hibernate.GlueHibernateSearch
  • com.poscoict.glueframework.biz.activity.hibernate.GlueHibernateUpdate
  • com.poscoict.glueframework.biz.activity.hibernate.GlueHibernateEntityCreator
  • com.poscoict.glueframework.biz.activity.hibernate.GlueHibernateEntityModifier
  • com.poscoict.glueframework.biz.activity.hibernate.GlueHibernateEntityRemover