다음과 같은 프로시져가 선언되어 있다고 하자.
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이 직접 도메인모델 객체에 매핑할수 없음을 말한다.
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로 잡아야 한다.)
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
}
또한 파라메터와 형식을 직접 설정할수도 있다.
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로 호출하면 된다.
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으로 받을수 있다.
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를 통해서 다루기로 한다. (다음에 계속...)
'이전글(~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 |
댓글을 달아 주세요