2012/03/17 22:57

도메인의 퍼시스턴스 계층을 담당할 Repository의 탄생 Domain Driven Design

DAO vs REPOSITORY

DAO는 데이터베이스에서 값을 꺼내와 도메인 오브젝트로 반환해주거나 적절한 값으로 반환해주는 계층을 일컫는다. Repository는 한 도메인 오브젝트에 대해서 객체의 값을 보증해주기 위해 도메인 내부에서 데이터베이스와 소통하는 객체을 일컫는다.

솔직히 필자가 Repository에 대해 어떠한 식견을 내세우기엔 너무 내공높은 개발자들이 무섭게 각을 내세우고 있는데다 Repository의 필요성 또한 갈수록 줄어드는 추세인 듯 하여 조금 비관적인 이야기로 시작해볼까한다. 

필자가 생각하는 프로그래밍이란 예술이나 문화의 범주에 속하는 것이 아니며 철저히 산업에 기반하는 학문의 일종이다. 그러므로 프로그래밍의 발전은 어디까지나 사용하는 기업의 입장, 그리고 개발자들의 업무상 요구하는 형태를 적극 반영하여 제작되어온데다 그동안 과거를 돌이켜 볼 때 기업과 개발자들의 지지를 받지 못한 기술은 곧잘 사라지곤 했었다.

무작정 다수결의 논리로 필요없어진 기술은 적자생존의 법칙에 따라 물러나야 한다는 이야기는 아니다. 왜냐하면 당장에 필요없어진 기술적 논리가 10년 뒤에 엄청난 발전을 가져오기도 하고 또 지금 잘나가는 기술이 한순간에 새로운 기술로 오버랩되어 사라지는 곳이 IT업계이니 말이다. 필자가 말하고자 하는 것은 당장에 DAO와 REPOSITORY가 너무 거대한 교집합의 영역을 갖고 있고 개발 시에 둘 모두를 함께 끌고 가기엔 코드의 중복이 너무도 심하다는 뜻이다.

프로그래밍의 발전이란 결국 리팩토링의 역사이며 지금의 모든 프로그래밍의 기술이 리팩토링에 기반했다해도 과언이 아닌데 두 계층을 지지하는 세력들의 충돌이 확고하다고 하여 DAO와 Repository의 코드중복은 무시한 채 둘 다 사용할 수는 없는 노릇이다. 필자는 어느 한쪽만은 지지하기 보다는 어느 정도 절충을 하여 개발자는 개발이 시작되기 전에 전반적인 흐름을 미리 파악하고 둘 중 어느 것을 사용할지 양자택일해야 한다고 생각한다.

DDD는 4Tier 아키텍쳐이며 굉장히 객체지향적인 설계를 가능케 하지만 반대로 굉장히 무겁고 어느 정도 성능에 무리를 많이 주는 방식이다. 만약에 당신이 이런 단점을 감안하고 속도보다 사용자의 입장을 고려해서 개발한다면 완전한 DDD 방식의 어플리케이션을 개발할 수가 있다. 이럴 경우엔 DAO보단 Repository를 작성하는 것이 어울릴 것이다. 반대로 당신이 어느 정도 속도도 고려하여 전체적인 어플리케이션의 로직의 중심이 Service 계층과 도메인 계층 사이에 두고 싶다면 DAO가 어울릴 것이다.

어디까지나 선택은 개발자의 몫이다. 다만 DAO와 Repository를 같이 사용하는 것은 아무리 내가 초보라지만 바보같은 짓 같다.

Repository

무엇을 사용하기에 앞서 DAO와 Repository는 무엇인지 간략하게 살펴보도록 하자. Repository는 저장소란 뜻을 가진 단어이다. 그리고 Repository는 DAO처럼 하나의 거대한 계층을 이루고 있지 않으며 도메인 오브젝트의 내부에 위치하여 해당 오브젝트만을 위한 기능을 제공해준다. 겸손한 DAO라고 보면 될 듯 싶다.

public class SimpleProduct implements Product {

private String id;
private String name;
private ProductRepository productRepository;

public String getName() {
if(name==null) return userReponsitory.getName(getId());
else return name;
}

… 중략 …
}  

이전 장을 꼼꼼히 읽어본 뒤에 위의 예제를 이해했다면 아마 많은 독자가 DAO와 Repository의 기능이 별반 다르지 않다는 사실을 알게 될 것이다. 실제로도 그렇다. 두 객체의 차이점은 DAO는 도메인 바깥에 위치해서 해당 도메인을 위한 기능 외에도 다양한 기능을 갖고 있다는 점과 Repository는 도메인 내부에 위치하여 오로지 도메인을 위해서만 동작한다는 점 뿐이지 똑같이 데이터베이스에 접근하는 액세스 포인트를 갖고 있다.

그러나 두 오브젝트의 개념은 미묘하면서도 확실히 차이를 두어야 할만큼 다르기 때문에 개발자가 분명히 해두어야할 부분이다. 만약 해당 Repository가 만약 도메인 외부에서도 떠돌아 다닌다면 그것은 더이상 Repository가 부를 수 없으며 분명한 DAO 객체이다. 반대로 오로지 도메인을 내부에만 위치하면 도메인을 위해서만 기능하는 DAO가 있다면 그것은 더이상 DAO 객체라 부를 수 없다. 그러므로 사전에 어플리케이션을 설계할 때 만약 당신이 서비스 계층을 고려하여 도메인 계층과 서비스 계층을 둘다 이용하는 것을 고려한다면 DAO를 적극 활용할 것이고 반대로 서비스 계층을 최소화 하고 도메인 계층에 대부분의 로직을 부여한다면 Repository를 이용하는 방식을 이용하게 될 것이다.

다음 장부터는 Domain Driven Design을 활용하여 직접 전자상거래 시스템을 기획, 설계하는 과정을 거쳐볼 것이다. 사실 DDD란 아직 MVC만큼이나 확고한 설계방침을 가진 아키텍쳐는 아니므로 개발자마다 독자적으로 해석한 메서드, 또는 클래스들이 존재하기 마련이다. 필자가 구현하는 전자상거래 또한 어느 정도 자해석된 영역이 존재할 수도 있다는 점을 유의해주길 바란다.


출처 - http://springmvc.egloos.com/543686



Posted by linuxism
,


스프링 2의 JPA 지원을 통해 데이터베이스 접근하기

이번 절에서는 JPA를 지원하는 스프링 2의 기능을 이용해 Employee와 Address POJO의 데이터베이스 접근 기능을 추가한다.

JPA ORM을 이용한 객체 영속성

정의한 서비스 인터페이스를 구현하기 위해 스프링 2의 기능 일부분과 이것을 지원하는 라이브러리를 가져올 필요가 있다. 물론 대안도 있다. 인터페이스 구현을 JDBC와 같은 표준 자바 데이터베이스 접근 기술을 사용해 각 메서드 별로 시작할 수 있다. 그렇지만 어떻게 스프링 2가 JPA와 함께 작동하는 지를 본 후에는, 작업을 스프링에 위임하는 것이 실질적으로 더 쉽다는 것에 매우 감사해 할 것이다.

스프링 2에서 사용하는 JPA 영속성은 EJB 3.0과 자바 EE 5 명세에 통합되어 있다. 스프링에서 데이터베이스 접근을 가능하게 해주는 가장 간단한 방법 중 하나지만 아직 표준적인 방법은 아니다.

스프링 프레임워크는 다른 객체-관계형 매핑(ORM) 기술을 통해 영속성을 항상 지원하지만, 매핑 작업은 써드 파티 비표준 영속성 라이브러리에 대해 상당히 까다롭고 깊은 지식을 필요로 한다. JPA에 이미 익숙한 사람과 JPA 표준을 지원하는 기반을 갖고 있는 규모가 큰 벤더들에게 비표준 써드 파티 영속성 라이브러리 지원은 크게 중요하지는 않을 수도 있다.

스프링 2의 JPA 지원은 객체(POJO)와 관계형 데이터베이스의 쓰고, 읽고, 검색하고, 수정하고, 삭제하는 지루한 작업들을 투명하게 만들어준다. POJO를 사용해 작업함으로써 자바 언어의 객체 지향 문법을 계속 사용할 수 있고, JPA ORM 레이어는 데이터베이스 테이블을 만들고, 조회하고, 수정하고, 삭제하는 코드를 책임지게 된다.

투명한 데이터베이스 오퍼레이션 외에도 스프링 2의 JPA 지원은 특정 데이터베이스 벤더에 특화된 예외의 모음(potpourri)에서, 예외 처리 코드를 매우 간단하게 만들어주는 정제된 예외의 집합으로 변환해 준다. 그림 5는 스프링 2의 JPA 지원을 설명하고 있다.


그림 5. 스프링 2의 JPA 지원
 

자바 SE 5 어노테이션과 더불어 JPA는 외부 XML 파일을 통해 매핑 정보 명세를 지원한다. 이 기술은 자바 SE 5를 사용할 수 없을 경우 필요하나 이 튜토리얼의 범위에서 벗어난다.

그림 5에서 어떻게 관계형 테이블과 매핑을 시킬 것인지에 대한 일부 정보(메타데이터)와 함께 객체들을 스프링 엔진에 제공한다. 스프링 JPA 지원은 다른 부분들에도 신경을 쓰고 있다. 자바 5 어노테이션이나 외부 XML 정의 파일(JDK 1.4와 호환되는)로 JPA 엔진에 매핑 정보를 제공할 수 있다.

JPA 구현체는 ORM 제품과 데이터베이스에 따라 다양하게 존재하기 때문에, 여러분이 구현한 코드를 다른 벤더의 솔루션에 (필요하다면) 이식할 수 있다.

매핑된 객체에 대한 오퍼레이션은 JPA 엔티티 매니저(entity manager)를 통해 수행된다. 예를 들어, em이라는 엔티티 매니저로 관련 객체의 트리를 관계형 데이터베이스로 기록하려면 코드는 다음과 같다.

em.persists(myObjectTree);

그리고 나서 JPA 엔티티 매니저는 제공한 매핑 힌트를 검사하고 myObjectTree를 통해 객체 트리의 모든 맵된 필드를 관계형 데이터베이스로 저장한다.

스프링 DAO를 사용한 도메인 서비스 구현에서 살펴보겠지만 스프링은 더 나아가 JPA 엔티티 매니저로 하는 작업을 단순화한다.




위로


JPA ORM 매핑 메타 데이터 제공하기

Employee 객체를 데이터베이스에 어떻게 저장할 것인지에 대한 정보를 제공하기 위해, Employee.java 소스 코드에 자바 SE 5 어노테이션을 추가할 수 있다. 이 정보는 데이터를 기술하는 데이터이기 때문에 흔히 메타 데이터로 불린다.

Listing 6은 Employee 객체의 어노테이션 버전을 보여준다. 어노테이션은 굵은 글씨로 강조했다.


Listing 6. Employee POJO에 JPA 어노테이션 추가하기
                    
package com.ibm.dw.spring2;

import java.util.Date;
import javax.persistence.CascadeType;
...
import javax.persistence.TemporalType;

@Entity
public class Employee {
   
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private long empid;

@Column(length = 6)
private String empno;

@Column(name = "FIRSTNME")
private String firstName;

@Column(name = "MIDINIT")
private String midInitial;

private String lastName;

@Column(name = "PHONENO")
private String phoneNumber;

@Column(length = 8)
private String job;

@Column(name = "EDLEVEL")
private int educationLevel;

@Column(length = 1)
private char sex;

@Column(precision=12, scale=2)
private double salary;

@Column(precision=12, scale=2)
private double bonus;

@Column(name = "COMM", precision=12, scale=2)
private double commission;

@OneToOne(cascade = CascadeType.ALL)
private Address addr;

@Temporal(TemporalType.DATE)
private Date hiredate;

@Temporal(TemporalType.DATE)
private Date birthdate;

...

여기에서 쓰인 모든 어노테이션은 필드 수준이다. 이 방법이 JPA 어노테이션의 가장 보편적인 사용방법이다. 또 필드의 대응되는 getter 메서드에 어노테이션을 붙일 수 있다. 데이터베이스에 저장하고 싶은 값이 객체의 필드가 하는 것 대신에 연산되는 경우에 필요하게 된다.




위로


Employee POJO에 적용된 JPA 어노테이션

표 1은 Listing 6에서 각 필드에 적용된 어노테이션과 이 영속성 정보가 스프링 2 엔진에 어떤 의미를 주는지 설명하고 있다.


표 1. Employee POJO에 적용된 JPA 어노테이션
필드 / 엘리먼트어노테이션설명
Employee@Entity이 클래스가 데이터베이스에 저장될 것을 나타냄. 기본적으로 클래스 이름이 테이블 이름으로 사용됨
empid@Id이 필드가 테이블의 주 키 필드가 됨을 나타냄
empid@GeneratedValue(strategy = GenerationType.TABLE)유일한 주 키 ID를 할당하는 영속성 엔진(persistence engine)에 의해 사용되는 전략을 기술함. GenerationType.TABLE은 이식성 있고 테이블 기반 시퀀싱의 유일한 ID가 사용되어야 함을 나타낸다. 다른 데이터베이스 기반 옵션도 사용할 수 있으나 여러 개의 데이터베이스에서는 작동하지 않을 수 있다.
empno@Column(length = 6)이 필드에는 회사에서 할당한 직원 번호가 들어있다. 이 어노테이션은 이 필드가 주 키가 아님에 주의하라. 이 애플리케이션에서 주 키는 엔진에 의해 (자동) 생성되며, 관리됨. @Column 태그는 이 필드는 길이가 6자리 문자까지 될 수 있다는 것을 나타냄. 적절하게 길이가 기술된 필드는 테이블 크기를 작게 유지하는 것을 도와줌.
firstName@Column(name = "FIRSTNME")데이터베이스 테이블의 필드에 사용될 필드 이름을 기술함
midInitial@Column(name = "MIDINIT")데이터베이스 테이블의 필드에 사용될 필드 이름을 기술함. 자바 필드 이름과는 차이가 있다는 것을 기억해야 함
lastName어노테이션이 없으므로, 필드 이름 "LASTNAME"이 자바 필드 이름에 맞춰 사용될 것이다.
phoneNumber@Column(name = "PHONENO")데이터베이스 테이블에서 사용될 필드 이름을 기술함
job@Column(length = 8)데이터베이스 필드의 길이를 기술함
educationLevel@Column(name = "EDLEVEL")데이터베이스 필드 이름을 기술함
sex@Column(length = 1)데이터베이스 필드의 길이를 기술함
salary@Column(precision=12, scale=2)데이터베이스 필드 소수점의 십진수 정밀성을 기술함
bonus@Column(precision=12, scale=2)데이터베이스 필드 소수점의 십진수 정밀성을 기술함
commission@Column(precision=12, scale=2)데이터베이스 필드 소수점의 십진수 정밀성을 기술함
addr@OneToOne(cascade = CascadeType.ALL)이 테이블과 또 다른 테이블에 매핑된 Address 객체의 관계를 기술함. cascade=ALL은 추가, 수정, 삭제, 리프레시 가 될 경우 관련된 테이블에 모두 영향을 미친다는 것을 의미한다.
hiredate@Temporal(TemporalType.DATE)이 필드는 date 필드라는 것을 기술함(time이나 timestamp 필드가 아닌)
birthdate@Temporal(TemporalType.DATE)이 필드는 date 필드라는 것을 기술함(time이나 timestamp 필드가 아닌)

Employee와 Address 인스턴스가 일대일 관계(@OneToOne(casecade=CascadeType.ALL)) 어노테이션으로 기술되어)를 맺고 있는 것을 기억하자. 이 어노테이션은 Employee 객체를 대상으로 하는 모든 엔티티 매니저 오퍼레이션이 그 객체와 관련된 Address 객체에도 영향을 준다는 것을 의미한다. 이 말은 RDBMS에 Employee 기록을 추가하는 어느 작업이든지 그에 대응하는 Address 기록도 만들어지는 것을 뜻한다. 이것은 RDBMS에서 종종 찾을 수 있는 연속되는 삭제 참조 무결성 개념의 확장된 개념이라 보면 되겠다. 실제로 연속되는 오퍼레이션을 수행할 때 자바 코드 양이 상당히 줄어드는 것을 쉽게 발견할 수 있으므로 더 이상 다수의 테이블에 걸쳐 영향을 미치는 오퍼레이션이 필요하지 않을 것이다.

어노테이션이 붙은 Employee 소스 코드는 JPA 엔티티 매니저가 Employee와 Address 객체의 영속성 인스턴스를 관리하는 데 청사진(blueprint)이 된다. 이 방법이 실제 RDBMS와 직접적으로 작업하면서 생성해야 하는 지루하고, 에러가 나기 쉬운 물리적인 코드보다 엄청날 정도로 더 간단함을 발견할 것이다.

위 어노테이션을 기반으로 생성된 Employee 객체에 해당하는 데이터베이스 테이블은 Listing 7과 스키마가 비슷하다.


Listing 7. Employee POJO를 위한 동일한 데이터베이스 스키마
                    
CREATE TABLE EMPLOYEE (
      EMPID INTEGER NOT NULL,
      EDLEVEL INTEGER,
      SEX CHAR(1),
      FIRSTNME VARCHAR(255),
      SALARY DOUBLE,
      LASTNAME VARCHAR(255),
      BONUS DOUBLE,
      JOB VARCHAR(8),
      COMM DOUBLE,
      MIDINIT VARCHAR(255),
      HIREDATE DATE,
      EMPNO VARCHAR(6),
      BIRTHDATE DATE,
      PHONENO VARCHAR(255),
      ADDR_ID INTEGER,
      PRIMARY KEY (EMPID),
      FOREIGN KEY (ADDR_ID)
   )
;

문자열 기반 필드의 길이

@Column(length=?) 어노테이션을 붙이지 않은 String 필드의 기본값은 VARCHAR(255)임을 기억하자. 이것은 각 행마다 짧은 길이의 필드로 될 것을, 기본값으로 하면 저장 공간을 허비할 수 있다는 것을 보여준다. 실제 제품에서는 관리해야 하는 테이블 내의 저장 공간 할당을 좀 더 엄격하게 관리하고 싶을 것이다.

스프링 엔진에 의한 테이블을 생성하는 어노테이션의 효과를 보기 위해 Listing 7을 Listing 6에 있는 어노테이션이 붙은 Employee 클래스와 비교해 보자.

JPA에서 가능한 모든 어노테이션에 대한 더 자세한 설명과 기술을 보길 원한다면, JSR 220, EJB 3.0 명세의 최종 릴리스 문서를 참조하라(참고자료).




위로


Address 객체를 위한 JPA 어노테이션

Listing 8 처럼, Address POJO에도 비슷한 방법으로 어노테이션을 붙였다.


Listing 8. Address POJO를 위한 JPA 어노테이션
                    
package com.ibm.dw.spring2;

import javax.persistence.Column;
...

@Entity
public class Address {

   @Id
   @GeneratedValue(strategy = GenerationType.TABLE)
   private long id;

   @Column(name = "NUM")
   private int number;

   @Column(name = "STNAME", length=25)
   private String street;
...

지금까지 모든 어노테이션을 잘 이해했을 것이다. Listing 8에 기술된 어노테이션과 매핑되는 테이블이 Listing 9에서 보여주는 스키마를 갖게 된다는 것은 놀랄 일도 아니다.


Listing 9. Address POJO에 동일하게 매핑되는 데이터베이스 스키마
                    
CREATE TABLE ADDRESS (
      ID INTEGER NOT NULL,
      NUM INTEGER,
      STNAME VARCHAR(25),
      PRIMARY KEY (ID)
   )
;




위로


스프링 2와 자바 EE 5와의 관계

JPA 영속성(persistence)은 EJB 3.0의 일부이자 뒤이어 자바 EE 5 명세의 일부가 됨으로써 호환되는 모든 자바 EE 5 서버(상용, 오픈 소스, 기타)는 이에 따르는 구현을 갖게 되었다. 이 덕분에 가까운 장래에 견고한 고품질의 JPA 구현체를 사용할 수 있음이 실질적으로 보장됐다.

비록 스프링 2가 EJB 3.0 명세에 있는 JPA 영속성을 활용은 하지만, 스프링 2 사용자들이 EJB 3.0이나 자바 EE 5 명세의 다른 요소에 따라야 하는 의무는 없음에 주의하라.

JPA는 전통적인 EJB 컨테이너 외부에서 독립적으로 편리하게 쓸 수 있도록 고안되었다. 구체적인 예로서 이 튜토리얼의 애플리케이션은 JPA 덕분에 혜택을 누리지만, EJB 3.0이나 자바 EE 5 애플리케이션은 분명히 아니다.


출처 - http://www.ibm.com/developerworks/kr/library/tutorial/j-spring2/section4.html








스프링 DAO를 사용한 도메인 서비스 구현

이번 절에서는 직원 정보 애플리케이션의 서비스 인터페이스 구현을 위해 스프링 DAO(Data Access Object) API를 사용한다.

EmployeeService 인터페이스 구현하기

일단 스프링 2 엔진이 Employee와 Address 객체의 인스턴스를 영속화하는 방식을 알면, EmployeeService 인터페이스 구현 작업은 상당히 간단해진다.

서비스 구현에 스프링 DAO API를 가져와 사용할 수 있다. 스프링 DAO는 잘 알려진 DAO 디자인 패턴(참고자료 참조)을 구현했다. 이 패턴에서 DAO는 데이터 접근을 위한 일관된 퍼사드(facade) 객체를 제공한다. 데이터를 받아오고 수정하는 작업은 객체 전송을 통해 수행된다. DAO는 실제 데이터 소스를 캡슐화해 객체 전송으로 작업을 할 수 있는 메서드를 제공한다.

아키텍처 관점으로 보면, DAO API는 실제 데이터 영속성 API를 호출해야 하는 작업의 복잡성으로부터 개발자들을 보호한다(JPA 외에도 스프링은 JDO, Hibernate, iBatis SQL Maps, 아파치 OJB와 같은 ORM을 지원한다). 스프링의 DAO를 이용해 이러한 영속성 API에 쉽게 채택할 수 있는 데이터 접근 코드를 작성할 수 있다.

데이터 영속성 API에 대한 추상화 외에도 스프링의 DAO는 벤더에 종속된 많은 데이터 접근 예외(data access exceptions)를 문서로 잘 설명되어 있는 스프링 데이터 접근 예외의 집합으로 변경해준다.

또한 스프링 DAO API는 확장할 수 있는 지원 클래스(support classes)를 제공한다. 이 클래스들을 확장함으로써 ORM 데이터 접근 코드를 작성해야 하는 지루하고, 에러 발생 위험이 큰 작업에서 해방될 수 있다. 필수적으로 쓰이는 코드는 전부 기본 클래스에 캡슐화되어 있으며, 라이브러리 클래스를 지원하고, 완벽히 테스트되어 있다. 이 클래스들은 종종 애플리케이션 로직으로 뒤범벅된 커넥션과 트랜잭션 관리 코드를 캡슐화해 준다. JPA 지원 클래스의 경우 JPA 엔티티 매니저 사용이 지원 클래스 내에서 완벽하게 캡슐화되어 있어, 엔티티 매니저와 엔티티 매니저 팩토리와의 직접적으로 관계된 작업에서 자유롭게 해준다.

실제 사용되는 코드를 보면 스프링 DAO API의 다재 다능함을 확신할 수 있을 것이다. Listing 10은 스프링 2의 JpaDaoSupport 클래스를 사용해 EmployeeDAO라는 EmployeeService 인터페이스를 구현한 것이다.


Listing 10. 스프링 2의 JPA 지원 클래스를 사용한 EmployeeService 인터페이스 구현
                    
import java.util.List;

import org.springframework.orm.jpa.support.JpaDaoSupport;

public class EmployeeDAO extends JpaDaoSupport implements EmployeeService {

   public Employee findById(long id) {
      return getJpaTemplate().find(Employee.class, id);
   }
    public List<Employee> findAll() {
       return getJpaTemplate().find("select e from Employee e");
    }
   public List<Employee> findByEmployeeNumber(String empno) {
      return getJpaTemplate().find(
      "select e from Employee e where e.empno = ?1", empno);
   }

   public List<Employee> findByAddressStreetName(String street) {
      return getJpaTemplate().find(
      "select e from Employee e where e.addr.street = ?1", street);
   }

   public List<Employee> findByEmployeeLastName(String lastName) {
      return getJpaTemplate().find(
      "select e from Employee e where e.lastName = ?1", lastName);
   }

   public List<Employee> findEmployeeWithSalaryOver(double sal) {
      return getJpaTemplate().find(
      "select e from Employee e where e.salary > ?1", sal);
   }

   public List<Employee> findEmployeeWithCommissionOver(double comm) {
      return getJpaTemplate().find(
      "select e from Employee e where e.commission > ?1", comm);
   }

   public Employee save(Employee emp) {

      getJpaTemplate().persist(emp);
      return emp;
   }

   public Employee update(Employee emp) {
      return getJpaTemplate().merge(emp);
   }

   public void delete(Employee emp) {
      getJpaTemplate().remove(emp);
         
   }
   
}

Listing 10에서, 첫 번째 기억할 것은 각각의 메서드 구현이 매우 간단하다는 것이다. JpaDaoSupport 클래스는 문제와 관련이 없지만, 문제 해결을 위해 일상적으로 해야 하는 지루한 많은 작업을 직접 관리해 준다. JpaTemplate는 헬퍼 클래스(helper class)다.

  • API 차이를 내부적으로 숨김
  • 예외를 번역
  • JPA 엔티티 매니저 관리
  • 트랜잭션 관리 감싸기(wrap)
  • 일관되고(모든 스프링 DAO 구현에 걸쳐) 잘 정제된 메서드를 위해 데이터 접근 표준화

표 2는 Listing 10에서 자주 사용되는 JpaTemplate 메서드를 요약하고 있다.


표 2. EmployeeDAO에 있는 JpaTemplate 메서드
메서드설명
find(Class <T> cls, Object id);주어진 주 키로 영속성 인스턴스를 찾아 온다.
find(String query);질의 문자열을 사용해 영속성 객체들을 찾아 옴. 여기에서 사용되는 질의는 EJB QL의 확장 버전으로 매우 강력한 질의 언어이며, 더 자세한 설명은 JSR-220에 있다(참고자료 참조).
persist(Object obj);데이터베이스에 인스턴스를 저장함. JPA에서는 JPA 엔티티 매니저를 사용해 인스턴스를 영속화한다고 말한다.
merge(Object obj);객체의 저장된 인스턴스를, 제공된 인스턴스에 있는 정보로 수정함
remove(Object obj);데이터베이스에 있는 영속성 인스턴스를 제거함

내부적으로 JpaTemplate 헬퍼 클래스는 모든 오퍼레이션을 처리하기 위해 JPA 엔티티 매니저를 사용한다. 이 헬퍼 클래스는 데이터 접근 작업 동안 엔티티 매니저의 종료와 데이터를 반환하는 일상적인 작업을 다룬다.

JpaTemplate 클래스에 있는 다른 메서드는 특별히 사용할 필요가 있을 때 매우 유용하게 쓰일 수 있다. 스프링 DAO API에 대한 더 자세한 정보는 JavaDoc을 참조하자(참고자료 참조).

Employee와 Address 인스턴스를 영속화하는 능력과 EmployeeService의 구체적인 구현을 사용할 수 있기 때문에, 이제 실제 관계형 데이터베이스와 연동해 모든 것을 테스트할 때다.




위로


스프링 빈 묶기

여기까지 살펴보면서도 언제 어떻게 스프링 프레임워크가 POJO와 작업할 수 있는 기회를 실제로 얻는지 여전히 분명하지 않을 것이다. 데이터 접근에 관련된 부분이 제자리에 있지만 두 가지 의문이 남아있다. 바로 무슨 일을 해야 하는지 스프링 2 엔진은 어떻게 아는가와 어떤 관계형 데이터베이스를 사용해야 할지 어떻게 지정하는가이다.

빈 와이어링(beans wiring) 템플릿을 스프링 엔진에 어떻게 제공하는지를 보면, 순식간에 이 두 미스테리를 풀 수 있을 것이다. 비밀은 dwspring-service.xml이라는 XML 빈 기술서(beans descriptor) 파일에 있다. 이 빈 기술서 파일은 '스프링 2 프레임워크 오퍼레이션 살펴보기'에서 본 스프링에 사용되는 청사진(blueprint)을 묶는 일을 한다. 이 파일은 스프링 애플리케이션에 있는 다양한 빈 사이의 관계를 기술한다. 이 파일은 Listing 11에 나와있다.


Listing 11. dwspring-service.xml 빈 기술서
                    
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="employeeService" class="com.ibm.dw.spring2.EmployeeDAO">
      <property name="entityManagerFactory" ref="entityManagerFactory"/>
   </bean>

   <bean id="entityManagerFactory" class=
   "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
            <property name="showSql" value="true"/>
            <property name="generateDdl" value="true"/>
            <property name="databasePlatform" 
                    value="oracle.toplink.essentials.platform.database.HSQLPlatform"/>
         </bean>
      </property>
      <property name="loadTimeWeaver">
         <bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver"/>
      </property>
   </bean>

   <bean id="dataSource" 
     class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
                    <property name="url" value="jdbc:hsqldb:mem:dwspring"/>
                    <property name="username" value="sa" />
                    <property name="password" value="" />
   </bean>

   <bean id="transactionManager" 
     class="org.springframework.orm.jpa.JpaTransactionManager">
      <property name="entityManagerFactory" ref="entityManagerFactory"/>
      <property name="dataSource" ref="dataSource"/>
   </bean>

</beans>

EmployeeDAO 구현을 테스트하기 위해 HSQLDB라는 인 메모리(in-memory) RDBMS를 사용한다(참고자료 참조). HSQLDB 바이너리는 "스프링 2 dependencies" 배포판에서 받을 수 있다.

Listing 11에서는 HSQLDB의 인스턴스를 구성하는 데 특별히 필요한 줄만 굵은 글씨로 보여준다. 나중에("RDBMS로 통합 테스트를 위한 DAO 작성하기"에서) HQSLDB 대신 DB2 Express-C로 통합 테스트를 수행하기 위해 어떻게 이 정보를 수정하는지 보게 될 것이다.

EmployeeDAO는 JpaDaoSupport 클래스를 실제로 확장하고 있다는 것을 기억하자. 이 클래스는 로딩되는 시점에 JPA EntityManagerFactory가 "주입(injected)"되는 것으로 예상된다. 그러므로 모든 데이터 접근 오퍼레이션에서 JPA EntityManager를 얻기 위해 이 팩토리를 사용할 수가 있다.

그림 6은 빈이 dwspring2-service.xml 파일 내에서 어떻게 함께 묶이는지를 시각적으로 보여준다.


그림 6. 빈 와이어링(wiring)을 위한 개요도
 

본질적으로 Listing 11은 스프링 2 엔진에 의해 생성되어야 하는 객체를 위한 묶기 계획이고, 그림 6은 이 객체들을 시각적으로 도식화해 보여준 것이다. Listing 11과 그림 6에서 기억해야 할 중요한 점은 EmployeeDAO 인스턴스가employeeService라는 빈을 통해 어떻게 얻어질 수 있느냐는 것이다. EmployeeDAO 인스턴스는 entityManagerFactory라는 또 다른 빈을 갖고 있는 entityManagerFactory로 불리는 속성을 갖고 있다.

   <bean id="employeeService" class="com.ibm.dw.spring2.EmployeeDAO">
      <property name="entityManagerFactory" ref="entityManagerFactory"/>
   </bean>

ref="" 표기법은 문맥(context)-보통 같은 파일-내에 정의되어 있는 또 다른 빈을 참조하는 것을 의미한다.




위로


의존성 주입(Dependency injection)

외부에서 생성된 객체에 속성을 채워주는 것을 주입(injection)이라 부른다. 좀더 명확하게 말하면 주입되는 객체가 종종 특유의 오퍼레이션에 의존성을 갖게 되기 때문에 의존성 주입(DI: Dependency Injection)이다. DI는 스프링의 전체 아키텍처를 통틀어 매우 비중 있게 쓰인다. DI는 의존성을 갖는 서비스를 룩업하거나 찾을(예를 들어, EntityManagerFactory를 룩업하는 것) 필요 없이 컴포넌트 코드를 작성할 수 있게 해준다. 대신 마치 의존하고 있는 객체를 이미 사용할 수 있는 준비가 된 것처럼 컴포넌트 코드를 작성하고, 실제 의존성은 스프링 엔진이 코드가 실행되기 전에 컴포넌트 인스턴스에 주입한다.

의존성 주입 응용

entityManagerFactory를 묶는 Listing 11 부터 내용을 잘 이해했다면, 스프링에 의해 다음과 같은 의존성이 주입된다는 것을 기억할 것이다.

  • dataSource
  • jpaVendorAdapter
  • loadTimeWeaver

dataSource 빈은 org.springframework.jdbc.datasource.DriverManagerDataSource의 인스턴스로 HSQLDB RDBMS의 인 메모리 인스턴스로 구성된다.

jpaVendorAdapter 속성에는 스프링 애플리케이션용 실제 JPA 구현체와 연결하는 빈이 주입된다. 이 예제의 경우 org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter 클래스를 통해 접근되는 JPA 참조 구현체를 사용한다. 다음 번에 이 클래스는 databasePlatform property 속성으로 구성되어야 한다. 이 속성은 oracle.toplink.essentials.platform.database.HSQLPlatform가 할당되며, 이 구성은 HQSLDB RDBMS에 대한 접근을 지원한다. 이 빈의 generateDdl 속성은 데이터 정의 언어(Data Definition Language) 스크립트를 생성하고, 실행할 것인지를 다룬다. 이 속성에 true 값이 할당된 경우, 데이터베이스 스키마는 이 빈이 로드될 때마다 다시 생성된다. 통합 테스트를 하기 위해 이 속성을 true로 해두길 바란다.

dataSource 빈의 설정으로 org.springframework.jdbc.datasource.DriverManagerDataSource의 인스턴스가 생성되었다. 이 빈에는 다음과 같은 정보가 매개변수화되어 있다.

  • HSQLDB 데이터베이스 드라이버
  • 생성한 인 메모리 데이터베이스 JDBC URL(JDBC URL의 mem 부분)
  • 사용자 이름과 패스워드(HSQLDB에서 기본값은 각각 sa와 ""이다)

마지막으로 의존성이 없는 transactionManager 빈은 차후에 통합 테스트에서 구성된다. 나중에 쓰일 테스팅 기반 클래스는 이 빈을 타입으로 찾기 때문에 이 빈은 아직 묶을 필요가 없다.

스프링 2의 빈 묶기에 대해 충분히 감이 왔을 것이다. 다음 절(RDBMS에 대해 수행하는 DAO 통합 테스트 작성하기)에서 다룰 단계인, 데이터베이스를 HSQLDB에서 DB2 Express-C로 어떻게 변경할 것인지에 대해서도 아이디어를 갖게 되었을 것이다.



출처 - http://www.ibm.com/developerworks/kr/library/tutorial/j-spring2/section5.html

Posted by linuxism
,



Recover MySQL root Password

by  on APRIL 18, 2006 · 244 COMMENTS· LAST UPDATED AUGUST 4, 2010

You can recover MySQL database server password with following five easy steps.

Step # 1: Stop the MySQL server process.

Step # 2: Start the MySQL (mysqld) server/daemon process with the --skip-grant-tables option so that it will not prompt for password.

Step # 3: Connect to mysql server as the root user.

Step # 4: Setup new mysql root account password i.e. reset mysql password.

Step # 5: Exit and restart the MySQL server.

Here are commands you need to type for each step (login as the root user):

Step # 1 : Stop mysql service

# /etc/init.d/mysql stop
Output:

Stopping MySQL database server: mysqld.

Step # 2: Start to MySQL server w/o password:

# mysqld_safe --skip-grant-tables &
Output:

[1] 5988
Starting mysqld daemon with databases from /var/lib/mysql
mysqld_safe[6025]: started

Step # 3: Connect to mysql server using mysql client:

# mysql -u root
Output:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 4.1.15-Debian_1-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>

Step # 4: Setup new MySQL root user password

mysql> use mysql;
mysql> update user set password=PASSWORD("NEW-ROOT-PASSWORD") where User='root';
mysql> flush privileges;
mysql> quit

Step # 5: Stop MySQL Server:

# /etc/init.d/mysql stop
Output:

Stopping MySQL database server: mysqld
STOPPING server from pid file /var/run/mysqld/mysqld.pid
mysqld_safe[6186]: ended
[1]+  Done                    mysqld_safe --skip-grant-tables

Step # 6: Start MySQL server and test it

# /etc/init.d/mysql start
# mysql -u root -p


출처 - http://www.cyberciti.biz/tips/recover-mysql-root-password.html




'DB > MySQL' 카테고리의 다른 글

mysql - 한글 정렬  (0) 2013.05.14
mysql 클러스터(cluster)  (0) 2013.03.08
linux 에서 mysql rpm version install  (0) 2013.01.03
mysql - join  (1) 2012.10.19
mysql - 사용자 정의 변수  (0) 2012.10.15
Posted by linuxism
,