The Data Access Object patternJ 2 EE 개발자 들 은 Data Access Object ( DAO ) 디자인 패턴 을 사용 하 여 저 수준 의 데이터 액세스 로직 과 고급 비즈니스 로직 을 분리 한다 . DAO 패턴 을 구현 하 는 것 은 단순히 데이터 액세스 코드 를 작성 하 는 것 이상 이 다 . 이 패턴 을 사용 하 여 저 수준 데이터 액세스 와 고급 비지니스 로직 을 분리 한다 . 전형 적 인 DAO 구현 에 는 다음 과 같 은 요소 들 이 있 다 . DAO 팩토리 클래스 DAO 인터페이스 DAO 인터페이스 를 구현 하 는 구체 적 클래스 데이터 전송 객체 들 ( 밸류 ( value ) 객체 ) 구체 적 인 DAO 클래스 에 는 특정 데이터 소스 로 부 터 데이터 에 액세스 하 는 데 쓰이 는 로직 이 포함 되 어 있 다 . 구조 Data Access Object patterclass diagramData Access Object pattersequence diagram 역할 Business Object : Business Object 는 Data 클라이언트 를 대표 한다 . 이것 은 Data source 에 접근 하 여 데이트 를 얻 거나 저장 하 는 것 을 목표 로 하 는 객체 이 다 . Business Object 는 SessioBean , Entity Bea 또는 별도 의 Java Object 로 구현 된다 . Data Access Object : Data Access Object 은 이 패턴 에서 중요 한 객체 이 다 . Data source 에 투명 한 접근 을 가능 하 게 하 기 위하 여 Data AccessObject 은 Business Object 을 위해 근본 적 인 데 이타 접근 를 추상 한다 . BusinessObject 은 Data AccessObject 에게 Data load 와 store 행위 를 Delegate 한다 . DataSource : Data source 구현 체 를 대표 한다 . Data source 는 RDBMS , OODBMS , XML repository , flat file system 등등 일 수 있 다 . Data source 는 또한 서로 다른 시스템 ( legacy / mainframe ) , 서비스 ( B 2 B service ) 또는 특정 한 종류 의 Repository ( LDAP ) 일 수 있 다 . Value Object ( Transfer Object ) : Data 전송 에 사용 되 는 전송 객체 를 대표 한다 . Data Access Object 패턴 에서 클라이언트 에게 전송 되 는 데이터 의 왕복 통신 비용 을 줄이 고 객체 화 된 데이터 를 전달 하 기 위해 사용 되 며 또 , 클라이언트 로부터 Data source 의 Data 을 갱신 하 기 위해 Data Access Object 에게 변경 데이터 를 전달 할 때 도 사용 된다 . 의도 Data 에 대한 접근 방법 은 Data Base 의 종류 에 종속 적 이 다 . 그런 종속 적 인 영향 이 다른 어플리케이션 에 전파 되 지 않 게 하 기 위해 Data Source 에 접근 하 는 추상 화 객체 를 사용 한다 . 예 제 소스 Class 소스 package dao ; public class Customer implements java . io . Serializable { int CustomerNumber ; String name ; String streetAddress ; String city ; public Customer ( ) {} public int getCustomerNumber ( ) { returCustomerNumber ;} public void setCustomerNumber ( int CustomerNumber ) { this . CustomerNumber = CustomerNumber ;} public String getCity ( ) { returcity ;} public void setCity ( String city ) { this . city = city ;} public String getName ( ) { returname ;} public void setName ( String name ) { this . name = name ;} public String getStreetAddress ( ) { returstreetAddress ;} public void setStreetAddress ( String streetAddress ) { this . streetAddress = streetAddress ;}} package dao ; public abstract class DAOFactory { public static final int CLOUDSCAPE = 1 ; public static final int ORACLE = 2 ; public static final int SYBASE = 3 ; public abstract CustomerDAO getCustomerDAO ( ) ;// public abstract AccountDAO getAccountDAO ( ) ;// public abstract OrderDAO getOrderDAO ( ) ; public static DAOFactory getDAOFactory ( int whichFactory ) { switch ( whichFactory ) { case CLOUDSCAPE : / / returnew CloudscapeDAOFactory ( ) ; case ORACLE : returnew OracleDAOFactory ( ) ; case SYBASE : / / returnew SybaseDAOFactory ( ) ; default : returnull ;}}} package dao ; import java . sql . *; public class OracleDAOFactory extends DAOFactory { public static final String DRIVER = " oracle . jdbc . driver . OracleDriver "; public static final String DBURL = " jdbc : oracle : thin : @ localhost : 1521 : topaz "; public static ConnectiocreateConnection ( ) {// DataBase Connectio 생성 returnull ;} public CustomerDAO getCustomerDAO ( ) { returnew OracleCustomerDAO ( ) ;}/* public AccountDAO getAccountDAO ( ) {// Oracle 용 AccountDAO 생성 returnew OracleAccountDAO ( ) ;} public OrderDAO getOrderDAO ( ) {// Oracle 용 OrderDAO 생성 returnew OracleOrderDAO ( ) ;}*/} package dao ; import java . util . Collection ; import java . util . HashMap ; import javax . sql . RowSet ; public interface CustomerDAO { public int insertCustomer ( Customer customer ) ; public booleadeleteCustomer ( int CustomerNumber ) ; public Customer findCustomer ( int CustomerNumber ) ; public booleaupdateCustomer ( Customer customer ) ; public RowSet selectCustomersRS ( HashMap where ) ; public C ollectioselectCustomersTO ( HashMap where ) ;} package dao ; import java . sql . *; import java . util . Collection ; import java . util . HashMap ; import java . util . HashSet ; import javax . sql . RowSet ; public class OracleCustomerDAO implements CustomerDAO { public OracleCustomerDAO ( ) {// 초기 화 }/*** 아래 의 메소드 는 실행 전 에 Connection 을 받 아 와야 합니다 . * Data Source 에 필요 한 작업 을 작성 합니다 . */ public int insertCustomer ( Customer customer ) {// 이렇게 받 아 와야 합니다 . Connectioconnectio = OracleDAOFactory . createConnection ( ) ; retur 0 ;} public booleadeleteCustomer ( int CustomerNumber ) { returfalse ;} public Customer findCustomer ( int CustomerNumber ) { returnew Customer ( ) ;} public booleaupdateCustomer ( Customer customer ) { returfalse ;} public RowSet selectCustomersRS ( HashMap where ) { returnull ;} public C ollectioselectCustomersTO ( HashMap where ) { returnull ;}} package dao ; import java . util . Collection ; import java . util . HashMap ; public class Client { public static void main ( String [ ] args ) { Client client = new Client ( ) ; client . exec ( ) ;} public void exec ( ) { DAOFactory oracleFactory = DAOFactory . getDAOFactory ( DAOFactory . ORACLE ) ; CustomerDAO custDAO = oracleFactory . getCustomerDAO ( ) ; Customer customer = new Customer ( ) ; customer . setCity ( " 서울 "); customer . setName ( " Lee YuChang "); int newCustNo = custDAO . insertCustomer ( customer ) ; customer = custDAO . findCustomer ( newCustNo ) ; customer . setStreetAddress ( " 서울 특별시 00 구 00 동 00 번지 "); customer . setName ( " 후 루 꾸 "); custDAO . updateCustomer ( customer ) ; custDAO . deleteCustomer ( newCustNo ) ; HashMap where = new HashMap ( ) ; where . put ( " city "," 서울 "); CollectiocustomersList = custDAO . selectCustomersTO ( where ) ;}} 참고 사항 트랜잭션 경계 설정 ( demarcation ) DAO 는 트랜잭션 객체 들 이 라는 것 을 반드시 기억 해야 한다 . DAO 에 의해 수행 되 는 각각 의 작동 ( 데이터 구현 , 업데이트 , 삭제 ) 은 트랜잭션 과 관련 있 다 . 따라서 트랜잭션 경계 설정 ( demarcation ) 개념 은 매우 중요 하 다 . 선언 적 ( Declarative ) 트랜잭션 경계 설정 프로그램 에 입각 한 ( Programmatic ) 트랜잭션 경계 설정 프로그래머 는 EJB 전개 디 스크립터 를 사용 하 여 트랜잭션 애 트리 뷰트 를 선언 한다 . 프로그래머 는 트랜잭션 로직 을 코딩 해야 한다 . 런타임 환경 ( EJB 컨테이너 ) 은 트랜잭션 을 자동 으로 관리 하 기 위해 이 애 트리 뷰트 를 사용 한다 . 이 애플리케이션 은 API 를 통해 트랜잭션 을 제어 한다 . DAO 를 설계 할 때 고려 사항 트랜잭션 은 어떻게 시작 하 는가 ? 트랜잭션 은 어떻게 끝나 는가 ? 트랜잭션 시작 을 담당 하 는 객체 는 무엇 인가 ? 트랜잭션 종료 를 담당 하 는 객체 는 무엇 인가 ? DAO 가 트랜잭션 의 시작 과 종료 를 담당 해야 하 는가 ? 이 애플리케이션 이 다중 의 DAO 를 통해 데이터 에 액세스 해야 하 는가 ? 트랜잭션 에 포함 될 DAO 의 수 는 ? 하나 의 DAO 가 또 DAO 에 대한 메소드 를 호출 할 수 있 는가 ? JTA 개요 Java TransactioAPI ( JTA ) 와 Java TransactioService ( JTS ) 는 J 2 EE 플랫폼 에 분산 트랜잭션 서비스 를 제공 한다 . 분산 트랜잭션 에 는 트랜잭션 매니저 와 한 개 이상 의 리소스 매니저 가 포함 된다 . 리소스 매니저 는 일종 의 영속 데이터 스토어 이 다 . 트랜잭션 매니저 는 모든 트랜잭션 참여 자 들 간 통신 을 조정 하 는 역할 을 담당 한다 . JTA 트랜잭션 은 JDBC 트랜잭션 보다 강력 하 다 . JDBC 트랜잭션 이 하나 의 데이터베이스 연결 로 제한 되 어 있 다면 JTA 트랜잭션 은 다중 의 참여 자 들 을 가질 수 있 다 . 다음 의 자바 플랫 폼 컴포넌트 중 어떤 것 이 든지 JTA 트랜잭션 에 참여 할 수 있 다 . JDBC 커넥션 JDO PersistenceManager 객체 JMS 큐 JMS 토픽 Enterprise JavaBeansJ 2 EE Connector Architecture 스 팩 에 호환 하 는 리소스 어댑터 JDBC 를 이용 한 트랜잭션 경계 설정 JDBC 트랜잭션 은 Connectio 객체 를 사용 하 여 제어 된다 . JDBC Connectio 인터페이스 ( java . sql . Connection ) 는 두 개 의 트랜잭션 모드 를 제공 한다 . ( auto - commit 과 manual commit ) . java . sql . Connection 은 트랜잭션 제어 에 다음 의 메소드 를 제공 한다 . public void setAutoCommit ( boolean ) public booleagetAutoCommit ( ) public void commit ( ) public void rollback ( ) JDBC 트랜잭션 경계 설정 을 이용 하 면 여러 개 의 SQL 문장 을 하나 의 트랜잭션 으로 결합 할 수 있 다 . JDBC 트랜잭션 의 단점 중 하나 는 트랜잭션 범위 가 하나 의 데이터베이스 연결 로 제한 되 어 있 다는 점 이 다 . JDBC 트랜잭션 은 다중 데이터베이스 로 확장 할 수 없 다 . JTA 를 이용 한 트랜잭션 경계 설정 JTA 로 트랜잭션 경계 를 설정 하 기 위해 애플리케이션 은 javax . transaction . UserTransactio 인터페이스 에 대한 메소드 를 호출 한다 . javax . transaction . UserTransactio 인터페이스 는 다음 의 트랜잭션 제어 메소드 를 제공 한다 . public void begin ( ) public void commit ( ) public void rollback ( ) public int getStatus ( ) public void setRollbackOnly ( ) public void setTransactionTimeout ( int ) JTA 트랜잭션 을 시작 할 때 이 애플리케이션 은 begin ( ) 을 호출 한다 . 트랜잭션 을 끝내 려면 commit ( ) 또는 rollback ( ) 을 호출 한다 . import javax . transaction . *; import javax . naming . *;// . .. InitialContext ctx = new InitialContext ( ) ; Object txObj = ctx . lookup ( " java : comp / UserTransaction "); UserTransactioutx = ( UserTransaction ) txObj ; utx . begin ( ) ;// . .. DataSource ds = obtainXADataSource ( ) ; Connectiocon = ds . getConnection ( ) ; pstmt = conn . prepareStatement ( " UPDATE MOVIES . .."); pstmt . setString ( 1 , " Spinal Tap "); pstmt . executeUpdate ( ) ;// . .. utx . commit ( ) ;// . .. JTA 와 JDBC 사용 하 기 개발 자 들 은 DAO 클래스 에서 저 수준 데이터 작동 에 JDBC 를 사용 하 곤 한다 . JTA 를 이용 하 여 트랜잭션 의 경계 를 설정 하 려면 javax . sql . XADataSource , javax . sql . XAConnection , javax . sql . XAResource 인터페이스 를 구현 하 는 JDBC 드라이버 가 필요 하 다 . 이러 한 인터페이스 를 구현 하 는 드라이버 는 JTA 트랜잭션 에 참여 할 수 있 게 된다 . XADataSource 객체 는 XAConnectio 객체 용 팩 토리 이 다 . XAConnection 는 JTA 트랜잭션 에 참여 하 는 JDBC 커넥션 이 다 . 애플리케이션 서버 의 관리 툴 을 사용 하 여 XADataSource 를 설정 해야 한다 . ( 애플리케이션 서버 문서 와 JDBC 드라이버 문서 참조 하 여 설정 한다 . ) J 2 EE 애플리케이션 은 JNDI 를 사용 하 여 데이터 소스 를 검색 한다 . 일단 애플리케이션 이 데이터 소스 객체 에 대한 레퍼런스 를 갖 게 되 면 이것 은 javax . sql . DataSource . getConnection ( ) 을 호출 하 여 데이터베이스 로 의 커넥션 을 획득 하 게 된다 . XA 커넥션 은 비 XA 커넥션 과 는 다르 다 . XA 커넥션 은 JTA 트랜잭션 에 참여 하 고 있 다는 것 을 언제나 기억 하 라 . XA 커넥션 은 JDBC 의 자동 커 밋 기능 을 지원 하 지 않 는다 . 또한 이 애플리케이션 은 XA 커넥션 상 에서 java . sql . Connection . commit ( ) 또는 java . sql . Connection . rollback ( ) 을 호출 하 지 않 는다 . 대신 UserTransaction . begin ( ) , UserTransaction . commit ( ) , UserTransaction . rollback ( ) 을 사용 한다 . 최상 의 접근 방법 선택 하 기 대부분 의 프로젝트 에서 대부분 은 JDBC API 를 사용 하 여 DAO 클래스 를 구현 한다 . 이 DAO 클래스 는 다음 과 같이 요약 된다 . 트랜잭션 경계 설정 코드 는 DAO 클래스 안 으로 임 베 딩 된다 . DAO 클래스 는 트랜잭션 경계 설정 에 JDBC API 를 사용 한다 . 콜러 가 트랜잭션 경계 를 설정 할 방법 은 없 다 . 트랜잭션 범위 는 하나 의 JDBC Connection 으로 제한 된다 . JDBC 트랜잭션 이 복잡 한 엔터 프라이즈 애플리케이션 에 언제나 적합 한 것 은 아니 다 . 트랜잭션 이 다중 DAO 또는 다중 데이터 페이스 로 확장 한다면 다음 과 같 은 구현 전략 이 보다 적합 하 다 . 트랜잭션 은 JTA 로 경계 설정 된다 . 트랜잭션 경계 설정 코드 는 DAO 와 분리 되 어 있 다 . 콜러 가 트랜잭션 경계 설정 을 담당 하 고 있 다 . DAO 는 글로벌 트랜잭션 에 참여 한다 . JDBC 접근 방법 은 간단 함 이 매력 이 다 . JTA 접근 방법 은 유연 성 이 무기 이 다 . 애플리케이션 에 따라 구현 방법 을 선택 해야 한다 . DAO 에서 의 예외 핸들링 DAO 패턴 을 구현 할 때 다음 사항 을 자문 해 보 와야 한다 . DAO 의 퍼블릭 인터페이스 의 메소드 들 이 검사 된 예외 를 던지 는가 ? 그렇 다면 어떤 예외 들 인가 ? DAO 구현 클래스 에서 예외 는 어떻게 처리 되 는가 ? DAO 메소드 는 의미 있 는 예외 를 던져야 한다 . DAO 메소드 는 java . lang . Exception 을 던져서 는 안 된다 . java . lang . Exception 은 너무 일반 적 이 다 . 근본 문제 에 대한 정보 를 제공 하 지 않 을 것 이 다 . DAO 메소드 는 java . sql . SQLExceptio 메소드 를 던져서 는 안 된다 . SQLException 은 저급 JDBC 예외 이 다 . DAO 는 JDBC 를 나머지 애플리케이션 에 노출 하 는 것 이 아니 라 JDBC 를 캡슐 화 해야 한다 . DAO 인터페이스 의 메소드 들 은 콜러 가 예외 를 처리 할 수 있 다고 합리 적 으로 판단 될 때 에 만 검사 된 예외 를 던져야 한다 . 콜러 가 예외 를 핸들 할 수 없 다면 검사 되 지 않 은 ( 런타임 ) 예외 를 던질 것 을 고려 하 라 . 데이터 액세스 코드 가 예외 를 잡 으면 이 를 무시 하 지 말 아라 . 잡힌 예외 를 무시 하 는 DAO 는 문제 해결 에 애 를 먹 는다 . 연쇄 예외 를 사용 하 여 저급 예외 를 고급 예외 로 트랜 슬 레이팅 한다 . 표준 DAO 예외 클래스 를 정의 하 라 . 공유 하 기 글 요소