11.4. Modeling JDBC operations as Java objects

DB를 좀더 객체지향적인 방법으로 접근하도록 다음의 클래스들을 사용할 수 있습니다. 다음의 클래스들로 할 수 있는 일은 모두(StoredProcedure 클래스만 빼고) JdbcTemplate에 있는 메소드를 사용하여 할 수 있습니다. 하지만 아래 있는 클래스를 사용하는 것이 편한 유저들을 굳이 말리진 않겠다는 군요.[footnote]if you feel that you are getting measurable value from using the RDBMS
operation classes, feel free to continue using these classes.[/footnote]

11.4.1. SqlQuery

SQL 쿼리를 객체화 한 것으로 재사용 가능하며 멀티쓰레드 환경에서 안전한 클래스입니다.
이 클래스를 상속하는 클래스는 반드시 newRowMapper(..) 메소드를 구현해야 합니다.
이 메소드는 ResertSet에 있는 각각의 row를 객체로 맵핑 시키는 일을 합니다.
보통은 row를 자바 클래스로 매핑하는 일을 좀 더 쉽게 하기 위해 구현해둔 MappingSqlQuery  클래스를 상속하여 사용합니다.

11.4.2. MappingSqlQuery

이 클래스를 상속할 때는 mapRow(..) 메소드를 구현해서 각 row를 객체로 매핑할 수 있도록합니다.
[#M_예제 코드 보기..|less..| 쿼리는 다음과 같이 이 클래스를 상속하여 생성자를 활용하여 만들어줍니다.
private class CustomerMappingQuery extends MappingSqlQuery {

   public CustomerMappingQuery(DataSource ds) {
       super(ds, “SELECT id, name FROM customer WHERE id = ?”);
       super.declareParameter(new SqlParameter(“id”, Types.INTEGER));
       compile();
   }

   public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {
       Customer cust = new Customer();
       cust.setId((Integer) rs.getObject(“id”));
       cust.setName(rs.getString(“name”));
       return cust;
   }
}

쿼리를 사용하기 위해서 위에서 만든 클래스의 객체를 만들고 쿼리의 파라미터에 들어갈 값을 객체의 배열로 넣어 줍니다.
public Customer getCustomer(Integer id) {
   CustomerMappingQuery custQry = new CustomerMappingQuery(dataSource);
   Object[] parms = new Object[1];
   parms[0] = id;
   List customers = custQry.execute(parms);
   if (customers.size() > 0) {
       return (Customer) customers.get(0);
   }
   else {
       return null;
   }
}_M#]11.4.3. SqlUpdate

update문을 나타내는 객체로 다음과 같이 사용합니다.
[#M_예제 코드 보기..|less..| public class UpdateCreditRating extends SqlUpdate {

   public UpdateCreditRating(DataSource ds) {
       setDataSource(ds);
       setSql(“update customer set credit_rating = ? where id = ?”);
       declareParameter(new SqlParameter(Types.NUMERIC));
       declareParameter(new SqlParameter(Types.NUMERIC));
       compile();
   }

   /**
    * @param id for the Customer to be updated
    * @param rating the new value for credit rating
    * @return number of rows updated
    */
   public int run(int id, int rating) {
       Object[] params =
           new Object[] {
               new Integer(rating),
               new Integer(id)};
       return update(params);
   }
}_M#]11.4.4. StoredProcedure

RDBMS에 있는 프로시져라는 것을 객체화 할 떄 사용한다고 하는데 gg… DB 공부 해야겠습니다.

11.4.5. SqlFunction

SQL 함수를 표현하는 클래스로 JdbcTemplate의 queryForXXX와 비슷한 기능을 합니다. 장점으로는 JdbcTempate을 만들지 않아도 됩니다.

단일 row를 위해 사용하며 좀 더 복잡한 쿼리를 표현하고 싶을 땐 StoredProcedure 나 SqlCall 를 사용하랍니다.
[#M_예제 코드 보기..|less..| SqlCall public int countRows() {
    SqlFunction sf = new SqlFunction(dataSource, “select count(*) from mytable”);
    sf.compile();
    return sf.run();
}_M#]

11.3. Controlling database connections

11.3.1. DataSourceUtils

JNDI 를 사용하여 connection을 얻어오고 필요 없을 때 반환할 때 사용할 수 있는 편리한 static 메소드들을 제공하는 클래스입니다.

11.3.2. SmartDataSource

Classes using this interface can query whether or not the Connection should be closed after an operation. Spring’s DataSourceUtils and JdbcTemplate classes automatically perform such a check.

11.3.3. AbstractDataSource

DataSource를 구현한 추상 클래스로 커스텀 DataSource 클래스르 만들고 싶을 때 이 클래스를 상속합니다.

11.3.4. SingleConnectionDataSource

SmartDataSource 를 구현하야 만든 클래스로 connection을 재사용합니다. 따라서 멀티쓰레드 환경에 적합하지 않으며 테스트 용도로 사용합니다.

11.3.5. DriverManagerDataSource

SmartDataSource 를 구현하여 만들었으며 매번 새로운 connection을 만들어서 사용합니다. 이것도 역시 테스트 용도로 사용하는 것 같습니다. 근데 위에 있는 거랑 정반대인데 언제 어떻게 쓰는건지는;;;

11.3.6. TransactionAwareDataSourceProxy

대상 DataSource를 감싸서 Spring Tracsaction 을 사용할 수 있는 프록시를 만드는 클래스 입니다. 이미 존재하고 있는 DataSource를 Spring JDBC와 Tracsaction 추상화 계층을 사용할 수 있도록 하는 클래스 인듯..

11.3.7. DataSourceTransactionManager

JDBC datasource를 위한 PlatformTransactionManager의 구현체입니다. dataSource 당 하나의 쓰레드를 보장합니다.

JtaTransactionManager는 못하는데 이 녀석은 커스텀 Isolation level을 제공합니다.

DataSourceUtils.getConnection(DataSource) 을 사용해서 JDBC connection을 가져오는 방법이 DataSource.getConnection 이 방법 보다 좋습니다. Spring 이 SQLException을 감싸서 만들어 둔 unchecked Exception을 던져주기 때문에~

11.2.2. NamedParameterJdbcTemplate

이전 글에서 JdbcTemplate을 사용하여 쿼리를 작성할 때 ? 를 사용하였는데요. 쿼리에 필요한 파라미터가 여러개 라면 ? 의 순서를 신경써야 하는 단점이 생깁니다.

이때 JdbcTemplate 클래스를 감싸고 있는 NamedParameterJdbcTemplate 클래스를 사용하면 됩니다.

getJdbcOperations() 메소드를 사용해서 감싸고 있는 JdbcTempate 객체를 받아와서 사용할 수 있습니다.

private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

public int countOfActorsByFirstName(String firstName) {

    String sql = “select count(0) from T_ACTOR where first_name = :first_name“;

    SqlParameterSource namedParameters = new MapSqlParameterSource(“first_name“, firstName);

    return namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
}

: 를 사용해서 ? 대신 sql의 파라미터에 이름을 줄 수 있습니다.

SqlParameterSource에는 위의 예제에 있는 MapSqlParameterSource와 아래 예제에 있는  BeanPropertySqlParameterSource 가 있습니다.

public int countOfActors(Actor exampleActor) {

    // notice how the named parameters match the properties of the above ‘Actor’ class
    String sql = “select count(0) from T_ACTOR where first_name = :firstName and last_name = :lastName”;

    SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);

    return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
}

11.2.1. JdbcTemplate

- query() :: select 문 사용
사용자 삽입 이미지위와 같이 다양한 query 메소드들을 제공하고 있습니다.

예제 코드들)

int rowCount = this.jdbcTemplate.queryForInt(“select count(0) from t_accrual”);

int countOfActorsNamedJoe
    = this.jdbcTemplate.queryForInt(“select count(0) from t_actors where first_name = ?”, new Object[]{“Joe”});

String surname = (String) this.jdbcTemplate
    .queryForObject(“select surname from t_actor where id = ?”, new Object[]{new Long(1212)}, String.class);

Actor actor = (Actor) this.jdbcTemplate.queryForObject(
    “select first_name, surname from t_actor where id = ?”,
    new Object[]{new Long(1212)},
    new RowMapper() {

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Actor actor = new Actor();
            actor.setFirstName(rs.getString(“first_name”));
            actor.setSurname(rs.getString(“surname”));
            return actor;
        }
    });

메소드에 들어가는 인자로 메소드를 구분할 수 있습니다.
(1) 문자열 하나만 들어가는 메소드는 그냥 쿼리문을 날리고 있습니다.
(2) 문자열과 객체 배열을 받는 메소드는 ? 에 매칭되는 인자를 배열로 넘깁니다. 좀 더 유연한 쿼리문을 작성할 때 사용할 수 있겠습니다.
(3) 클래스 타입을 넘기는 메소드는 쿼리의 결과가 해당 객체의 타입을 알려줍니다.
(4) RowMapper 콜백을 넘기는 메소드는 resultSet의 각 요소를 객체에 매핑하는 역할을 합니다.

- update() :: insert, update, delete 문 사용
사용자 삽입 이미지사용법은 execute()랑 비슷합니다.

this.jdbcTemplate.update(“insert into t_actor (first_name, surname) values (?, ?)”, new Object[] {“Leonor”, “Watling”});

this.jdbcTemplate.update(“update t_actor set weapon = ? where id = ?”, new Object[] {“Banjo”, new Long(5276)});

this.jdbcTemplate.update(“delete from orders”); // :)

Data access using JDBC

11.1. Introduction

Spring 프레임워크의 JDBC 추상화 계층이 제공하는 장점들은 다음과 같으며 저 중에서도 굵은 글자 부분만이 개발 할 때 코딩이 필요한 부분입니다.

connection 정보 정의 하기
connection 열기
statement 만들기(쿼리 작성)
statement 객체 준비하고 실행하기
resultSet 을 이터레이션 돌기 위한 루프 세팅
각 이터레이션 마다 작업 하기
예외 처리
트랜잭션 처리
connectino 닫기

JDBC 추상화 프레임웤쪽의 패키지 구조를 살펴봅니다.(이전 까진 패키지 구조 살펴본적이 없었던 것 같은데.. 신기하군요. 허헐)

org.springframework.jdbc.core :: JdbcTemplate 클래스가 포함되어 있고 콜백 인터페이스들과 관련된 클래스들이 있습니다.

org.springframework.jdbc.datasource :: DataSource 에 편하게 접근하기 위한 utility 클래스들과 DataSourceTransactionManager 를 제공합니다.

org.springframework.jdbc.object :: RDBMS에서 사용하는 쿼리, 업데이트 등을 나타내는 클래스들을 제공합니다.

org.springframework.jdbc.support :: SQLException 을 바꾸기 위한 클래스들과 몇몇 유틸을 제공합니다.

11.2. Using the JDBC Core classes to control basic JDBC processing and error handling

JdbcTemplate, NamedParameterJdbcTemplate, SimpleJdbcTemplate, DataSource, SQLExceptionTranslator 클래스들 사용법을 살펴 봅니다.

11.3. Controlling database connections

DataSourceUtils 클래스와 다양한 DataSource 클래스들을 살펴 봅니다.

11.4. Modeling JDBC operations as Java objects

org.springframework.jdbc.object 패키지의 클래스들은 DB를 보다 OO적인 방식으로 접근할 수 있도록 도와줍니다.

SqlQuery, MappingSqlQuery, SqlUpdate, StoredProcedure, SqlFunction 클래스를 살펴 봅니다.