블로그 이미지
Max.

calendar

          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

Notice

2008.08.26 22:06 이전글(~2009)
SimpleJdbcCall클래스는 스토어드프로시져나 메타데이터를 이용한 조회를 단순화 시켜준다.
다음과 같은 프로시져가 선언되어 있다고 하자.
CREATE PROCEDURE read_actor (
IN in_id INTEGER,
OUT out_first_name VARCHAR(100),
OUT out_last_name VARCHAR(100),
OUT out_birth_date DATE)
BEGIN
SELECT first_name, last_name, birth_date
INTO out_first_name, out_last_name, out_birth_date
FROM t_actor where id = in_id;
END;

이 프로시져를 SimpleJdbcCall를 이용해서 조회하는 예제는 아래와 같다. SimpleJdbcInsert와 같이 초기화시 withProcedureName()메서드를 통해서 프로시져 메다데이터를 읽어 온다. 결과값을 Map으로 받아서 직접 도메인 모델 객체에 set 하고 있다. 이것은 SimpleJdbcCall이 직접 도메인모델 객체에 매핑할수 없음을 말한다.

public class JdbcActorDao implements ActorDao {
  private SimpleJdbcTemplate simpleJdbcTemplate;
  private SimpleJdbcCall procReadActor;
  public void setDataSource(DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    this.procReadActor =
    new SimpleJdbcCall(dataSource)
    .withProcedureName("read_actor");

  }
  public Actor readActor(Long id) {
    SqlParameterSource in = new MapSqlParameterSource()
    .addValue("in_id", id);
    Map out = procReadActor.execute(in);
    Actor actor = new Actor();
    actor.setId(id);
    actor.setFirstName((String) out.get("out_first_name"));
    actor.setLastName((String) out.get("out_last_name"));
    actor.setBirthDate((Date) out.get("out_birth_date"));
    return actor;
  }
  // ... additional methods
}

주의 할것은 프로시져 변수명화 out.get()파라메터명이 일치해야 하는것이다. DB 밴더에 따라서 대소문자가 구별될수 있다.

위에서 SimpleJdbcCall은 도메인모델 객체를 리턴하지 않는다고 언급하였는데, 외부 클래스를 이용하여 도메인모델 객체를 리턴할수 있다. 바로 CaseInsensitiveMap를 이용하는 것인데 이것은 Jakarta Commons project에서 Spring이 차용한것이다. 이용하는 방법은 setResultsMapCaseInsensitive() 메서드를  'ture'로 설정하고 사용하면 된다. (또한 commons-collections.jar를 classpath로 잡아야 한다.)

public class JdbcActorDao implements ActorDao {
  private SimpleJdbcCall procReadActor;
  public void setDataSource(DataSource dataSource) {
     JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
     jdbcTemplate.setResultsMapCaseInsensitive(true);
     this.procReadActor =
     new SimpleJdbcCall(jdbcTemplate)
     .withProcedureName("read_actor");
  }
  // ... additional methods
}


또한 파라메터와 형식을 직접 설정할수도 있다.

public class JdbcActorDao implements ActorDao {
  private SimpleJdbcCall procReadActor;
  public void setDataSource(DataSource dataSource) {
     JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
     jdbcTemplate.setResultsMapCaseInsensitive(true);
     this.procReadActor =
     new SimpleJdbcCall(jdbcTemplate)
     .withProcedureName("read_actor")
     .withoutProcedureColumnMetaDataAccess()
     .useInParameterNames("in_id")
     .declareParameters(
         new SqlParameter("in_id", Types.NUMERIC),
         new SqlOutParameter("out_first_name", Types.VARCHAR),
         new SqlOutParameter("out_last_name", Types.VARCHAR),
         new SqlOutParameter("out_birth_date", Types.DATE)
     ); 
  }
  // ... additional methods
}


지원하는 타입은 거의 모든 RDMS는 지원한다.
(Derby, DB2, MySQL, Microsoft SQL Server, Oracle, Sybase)

스토어드평션을 호출할때는 withFunctionName로 설정하고, executeFunction로 호출하면 된다.

CREATE FUNCTION get_actor_name (in_id INTEGER)
RETURNS VARCHAR(200) READS SQL DATA
BEGIN
DECLARE out_name VARCHAR(200);
SELECT concat(first_name, ' ', last_name)
INTO out_name
FROM t_actor where id = in_id;
RETURN out_name;
END;

소스는 아래와 같다.

public class JdbcActorDao implements ActorDao {
  private SimpleJdbcTemplate simpleJdbcTemplate;
  private SimpleJdbcCall funcGetActorName;

  public void setDataSource(DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    jdbcTemplate.setResultsMapCaseInsensitive(true);
    this.funcGetActorName =
    new SimpleJdbcCall(jdbcTemplate)
    .withFunctionName("get_actor_name");
  }

  public String getActorName(Long id) {
    SqlParameterSource in = new MapSqlParameterSource()
    .addValue("in_id", id);
    String name = funcGetActorName.executeFunction(String.class, in);
    return name;
  }
  // ... additional methods
}

프로시져를 이용해서 ResultSet를 리턴하고 싶다면 returningResultSet()메서드에 RowMapper로 도메인모델 객체를 넘겨주고 Map으로 받을수 있다.

CREATE PROCEDURE read_all_actors()
BEGIN
SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a;
END;

만약 결과값이 없으면 어떠 파라메터값도 가지지 않는다.

public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcCall procReadAllActors;

  public void setDataSource(DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    jdbcTemplate.setResultsMapCaseInsensitive(true);
    this.procReadAllActors =
    new SimpleJdbcCall(jdbcTemplate)
    .withProcedureName("read_all_actors")
    .returningResultSet("actors",
    ParameterizedBeanPropertyRowMapper.newInstance(Actor.class));

  }

  public List getActorsList() {
    Map m = procReadAllActors.execute(new HashMap<String, Object>(0));
    return (List) m.get("actors");

  }
  // ... additional methods
}

Map의 파라메터가 callee와 caller가  "actors"로 동일하다.

이후 언급되는 것은 고급기법으로 여기서는 생략하다.
11.6 Modeling JDBC operations as Java objects
11.7 Common issues with parameter and data value handling(BLOB,CLOB)
나중에 기회가 되면 실예제로 설명한다.


이상 11장 Data access using JDBC 개념적인 것은 끝났고, Demo Project를 통해서 다루기로 한다. (다음에 계속...)

'요즘은 거의 안쓰는 SpringJDBC라 그런지 별로 재미가 없다....ㅡㅡ;'
신고

'이전글(~2009)' 카테고리의 다른 글

진짜목적을 달성하기 위해서  (2) 2008.08.27
[서적] 부의 역사  (2) 2008.08.27
[SpringJDBC] SimpleJdbcCall  (0) 2008.08.26
[SpringJDBC] SimpleJdbcInsert  (0) 2008.08.26
[SpringJDBC] SimpleJdbcTemplate  (0) 2008.08.26
[SpringJDBC] Batch  (0) 2008.08.26
posted by Max.