본문 바로가기

IT 살이/04. 기술 - 프로그래밍

개발 프레임워크 만들기 대장정 29 - Spring.NET의 데이터 액세스 I

일반적인 기업형 애플리케이션은 대부분 N티어 구조를 갖는다.   다음 그림은 간단한 N티어 애플리케이션을 표현하고 있다. 참고로  티어는 물리적인 의미이고 레이어는 논리적인 의미라고 한다.

물리적으로 UI 레이어는 웹 애플리케이션의 경우는 웹 서버 그리고 윈폼 애플리케이션은 클라이언트 PC가 될 것이다. 그리고 서비스 레이어와 데이터 액세스 레이어는 보통 하나의 미들티어 서버에 존재한다. 물론 더 복잡한 물리적 구조로도 존재할 수 있다. 

Spring.NET의 IoC 컨테이너는 UI 애플리케이션 서버(PC)에서도 적용가능하고 미들티어 서버에서도 적용가능하다. 앞 포스트까지는 UI를 제공하는 웹 서버/사용자 PC 또는 미들티어 서버에서 실행될 수 있는 IoC 컨테이너에 대한 얘기를 했다. 그리고 UI 서버와 비즈니스 서버간의 통신 방법중의 하나인 웹 서비스에 대한 Spring.NET의 지원 얘기도 했다.

이제 남아 있는 큰 주제는 Spring.NET의 트랜잭션과 데이터 액세스 지원 얘기이다. 트랜잭션 이야기를 먼저 할지 데이터 액세스 이야기를 먼저 할지 고민하다 데이터 액세스부터 하기로 결정했다. 왜냐면 참고 문서를 읽다 보니까 그쪽이 먼저 이해가 되었다. 


■ Spring.NET의 Data액세스 지원


Spring.NET에서는 DB에 접근할 때 ADO.NET 기술을 이용할 수도 있고, NHibernate기술을 이용할 수도 있다.  우선 ADO.NET을 이용하는 기술을 알아본다. ADO.NET이 제공하는 .NET 프레임워크의 표준 API를 이용해서 DB에 접근할 수도 있다. 그렇지만 Spring.NET에서는 ADO.NET 기술을 한번 래핑한 API를 제공하는데 이 API를 사용하면 편리하다.

Spring.NET에서 제공하는 래핑 API도 두 종류로 구분할 수 있다. 하나는 "template"기반의 방식이고 하나는 객체 지향 기반의 방식이다(  이런 이름이 붙여진 것이 이해는 개인적으로 이해는 된다. 그렇지만 불행히도 지금 이것을 말로 표현할 정도는 아니다). 여튼 하나는 템플릿 방식이고 하나는 객체 지향 방식인가보다 -_-;; 이 방식에 따라서 사용자의 DB 접근 프로그래밍 스타일이 달라진다.

"template"기반의 방식을 이용하면 DB에 접근해서 작업을 하는데 AdoTemplate라는 클래스를 사용하게 된다. 즉 데이터 액세스 레이어의 객체( Data Access Object, 이하 DAO로 표현한다 )는 AdoTemplate객체를 사용해서 모든 DB 작업을 하게 된다.

객체 지향 기반의 DB 접근 방식에서는 DB에 대한 작업을 구분해서 각 작업을 클래스화했다. DB에 대한 작업은 그 성격에 따라 C( Create), R( Read), U( Update), D( Delete ) 나뉠 수 있다. 이 중에서 CUD작업은 DB에 영향을 미치기는 하나 조회하는 값이 없다. 이런 작업을 위해서 AdoNonQuery 타입을 제공하고 있고 그리고 읽기 전용의 작업을 위해서 AdoQuery 타입을 제공한다. 그리고 저장 프로시져를 이용하는 작업을 위해서 StoredProcedure라는 타입을 제공하고 있다. 그러나 이 방식의 DB 접근은 아직 널리 사용되지는 않은 모양이다.

이 포스트에서는 AdoTemplate객체를 이용하는 "template"기반의 방식를 설명할 것이다. 만약 객체 지향 기반의 프로그래밍 스타일을 알고 싶다면 Spring.NET에서 제공하는 레퍼런스 문서의 20.15절을 참고하기 바란다( 링크하나 걸어주고 싶은데 맘뿐이다. 쓰으...).


▶ AdoTemplate이용 구조


AdoTemplate를 이용해서 DB 데이터에 액세스하는 작업을 초 간단히 개념적으로 그렸다.

클라이언트 코드라 함은 여기서는 DAO( 데이터 액세스 객체)가 된다. 클라이언트 코드는 Spring.NET 프레임워크의 AdoTemplate에서 콜백될 객체를 넘겨준다. "콜백된다"는 것은 "다시 호출된다"는 의미로 쉽게 생각하자. 그러니까 AdoTemplate객체는 클라이언트 코드에서 넘겨받은 "콜백 객체를 다시 호출"하게 된다. 물론 AdoTemplate도 콜백객체를 어떻게 호출할지를 사전에 알 수 있다. 어떻게 아는지는 뒤에 보자. 야튼 이때 콜백 객체를 호출할때 AdoTemplate은 command 객체라는 것을 생성해서 호출 인자로 넘겨준다. command 객체에는  DB 액세스에 필요한 커넥션 정보가 포함되어 있다. 그리고 호출하는 클라이언트 코드의 트랜잭션 컨텍스트를 바탕으로 한 트랜잭션 정보도 설정되어 있다. AdoTemplate 객체를 작업하면 개발자가 작성한 소스에 DB 커넥션 정보나 트랜잭션 정보를 설정하는 코드는 없어도 된다는 이야기다.  콜백 객체에서는 넘겨받은 command 객체를 이용해서 이제 DB를 대상으로 실행 명령( sql문 또는 저장 프로시져 등 )을 수행하면 된다. 

방금 AdoTemplate 객체가 클라이언트 코드에서 넘겨받은 콜백 객체를 어떻게 호출할 수 있는지 알 수 있다고 했다. 이것은 AdoTemplate에서도 알고 있는 인터페이스와 델리게이트를 사용하기때문이다. 다시 말하면 클라이언트 코드에서 넘어오는 사용자 정의 콜백 객체는 AdoTemplate도 인식할 있는 사전에 정의한 인터페이스 또는 델리케이트를 구현한 객체여야 한다는 조건이 있다. 그 인터페이스와 델리게이트의 타입으로 ICommandCallback, CommandDelegate 정의가 되어 있다. 아래 그림에서는 이런 인터페이스 또는 델리게이트 기반의 콜백 구조를 보여주고 있다.


▶ ICommandCallback, CommandDelegate 기반의 콜백 구조


클라이언트 코드에서는 AdoTemplate객체의 Execute() 메소드를 호출할때 콜백 객체를 넘겨준다. 다음 그림을 보자. 

 

AdoTemplate 클래스에는 Execute() 메소드가 파라미터 타입에 따라서 여러 버전이 존재한다. 즉 ICommandCallback 또는 CommandDelegate이외의 다른 인터페이스, 델리게이트 객체를 받을 수도 있다는 것이다. 그림에서는 그 중에서 대표적인 두 개의 Execute() 버전을 보여주고 있다. 하나는 인터페이스 ICommandCallbakc 타입의 객체 c 를 받고 다른 하나는 델리게이트 CommandDelegate 객체 d를 받고 있다.

ICommandCallback 파라미터를 받는 버전을 먼저 보자. 우선 호출하는 코드의 컨텍스트에서 정보( DB 커넥션 정보, 트랜잭션 정보)를 구해서 command 객체를 생성한다. 그런 다음 파라미터로 받은 ICommandCallback 객체 c의 DoInCommand() 메소드를 호출하면서 콜백 객체로 방금 생성한 command객체를 넘겨준다. 이제 사용자 정의 콜백객체의 DoInCommand()에서는 넘겨받은 command객체를 이용해서 DB에대해서 명령을 수행한다.  이때 command객체에는 DB 액세스에 필요한 커넥션 정보, 실행 명령(sql, 저장 프로시져등)가 있다.

CommandDelegate 타입의 객체 d를 받는 Execute() 버전도 유사하게 작동한다. 역시 호출하는 클라이언트 코드의 컨텍스트에서 필요한 정보를 얻어서 command 객체를 생성한다. 그런 다음 넘겨받은 델리게이트 객체 d를 호출해서 command 객체를 콜백 객체로 넘겨준다. command 객체를 넘겨받은 콜백 객체의 사용자 정의 콜백함수에서는 command 객체를 이용해서 DB 액세스를 하게 된다. 이제 이 콜백 구조를 이용하는 샘플 코드를 보자.


▶  AdoTemplate를 이용하는 샘플 코드


이건 다음에 하자.