스프링처럼 jdbc 리팩터링하기

Post on 12-Apr-2017

433 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

한국 스프링 사용자 모임 (http://ksug.org) 1

Refactoring JDBC programming

2008.10.12박찬욱

한국 스프링 사용자 모임 (http://ksug.org) 2

1. Hand-made JdbcTemplate1.1 문제 인식 공유

1.2 해결 방안 모색

1.3 Refactoring with Strategy pattern

2. Spring JdbcTemplate2.1 Best Practice of JDBC Strategy

2.2 Simplify JDBC operation

Table of Contents

한국 스프링 사용자 모임 (http://ksug.org) 3

오늘의 목표는 ?•Composition + interface-based 프로그래밍 기법

Spring JdbcTemplate 이해하기

어디 쓸 만한 곳이 없을까 ?

4 한국 스프링 사용자 모임 (http://ksug.org)

1. Hand-made JdbcTemplate

한국 스프링 사용자 모임 (http://ksug.org) 5

1.1 문제 인식 공유• 퀴즈

– iBatis– ORM(Hibernate or TopLink 등 )– 내부 추상화 프레임웍– 쌩 (pure) JDBC~?

한국 스프링 사용자 모임 (http://ksug.org) 6

1.1 문제 인식 공유• JDBC 근본적인 문제

– TCFTC• Try-Catch-Finally-Try-Catch• 최고의 boilerplate 코드

– Connection / Resource 누수 문제– SQLException

• 데이터베이스 벤더 별로 정의된 error code, error state 정보

Connection con = null; Statement stmt = null; try { con = dataSource.getConnection(); stmt = con.createStatement(); stmt.executeUpdate(“UPDATE TABLE_NAME SET...”); }catch(SQLException e){ // 예외 처리 ...}finally { if (stmt != null) { try { stmt.close(); } catch (SQLException ex) {} } if (con != null) try { con.close(); } catch (SQLException ex) { } }

한국 스프링 사용자 모임 (http://ksug.org) 7

1.1 문제 인식 공유• 전혀 OO 스럽지 않은 반복적인 코드 (boilerplate code) 의

사용으로 Data Access 코드가 드러워져 간다

“Bad Java code is bad J2EE code.”- Rod Johnson

한국 스프링 사용자 모임 (http://ksug.org) 8

1.2 해결 방안 모색

Strategy pattern 을 도입해서 문제 해결 시도

한국 스프링 사용자 모임 (http://ksug.org) 9

1.2 해결 방안 모색• Strategy pattern 이란 ?

– 실행 시점에 (at runtime) 알고리즘을 선택할 수 있는 방법

한국 스프링 사용자 모임 (http://ksug.org) 10

1.2 해결 방안 모색• 왜 Strategy pattern 을 택했나 ?

- Programming to Interface instead of Concrete Class (Achieving Loose Coupling with Interface)

- Favor object composition over class inheritance (Prefer Object Composition to Concrete Inheritance)

한국 스프링 사용자 모임 (http://ksug.org) 11

2.1 Best Practice of JDBC Strategy• Strategy pattern

참조 : wiki[2]

한국 스프링 사용자 모임 (http://ksug.org) 12

1.3 Refactoring with Strategy pattern• 변경되는 부분과 그렇지 않은 부분 식별하기 , 각각

– Updating sql 실행try {

// get DB connectioncon = getConnection();

// create Statementstmt = con.prepareStatement( "update LECTURE SET name=? where ID=?“);

// binding sql parameterstmt.setString(1, name);//...

// execute Queryresult = stmt.executeUpdate();

} catch (SQLException exception) {// 예외처리

} finally {if (stmt != null) { try {stmt.close();}catch(SQLException e){}}// end ifif (con != null) { try {con.close();}catch(SQLException e){}}// end if

}// end try-catch-finallyreturn result;

try {// get DB connectioncon = getConnection();

// create Statementstmt = con.prepareStatement( "insert into LECTURE values(?, ?, ?, ?, ?)“);

// binding sql parametersstmt.setInt(1, incrementer.nextIntValue());// ...

// execute Queryresult = stmt.executeUpdate();

} catch (SQLException exception) {// 예외처리

} finally {if (stmt != null) { try {stmt.close();}catch(SQLException e){}}// end ifif (con != null) { try {con.close();}catch(SQLException e){}}// end if

}// end try-catch-finallyreturn result;

update() insert()

한국 스프링 사용자 모임 (http://ksug.org) 13

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementstmt = con.prepareStatement( "update LECTURE SET name=? where ID=?“);

// binding sql parameterstmt.setString(1, name);//...

// execute Queryresult = stmt.executeUpdate();

} catch (SQLException exception) {// 예외처리

} finally {if (stmt != null) { try {stmt.close();}catch(SQLException e){}}// end ifif (con != null) { try {con.close();}catch(SQLException e){}}// end if

}// end try-catch-finallyreturn result;

메소드 인자로 빼냄

콜백 메소드로 구현

공통 메소드로 추출

update()insert()

한국 스프링 사용자 모임 (http://ksug.org) 14

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementstmt = con.prepareStatement( "update LECTURE SET name=? where ID=?“);

// binding sql parameterstmt.setString(1, name);//...

// execute Queryresult = stmt.executeUpdate();

} catch (SQLException exception) {// 예외처리

} finally {if (stmt != null) { try {stmt.close();}catch(SQLException e){}}// end ifif (con != null) { try {con.close();}catch(SQLException e){}}// end if

}// end try-catch-finallyreturn result;

update()insert()

한국 스프링 사용자 모임 (http://ksug.org) 15

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementstmt = con.prepareStatement( "update LECTURE SET name=? where ID=?“);

// binding sql parameterstmt.setString(1, name);//...

// execute Queryresult = stmt.executeUpdate();

} catch (SQLException exception) {// 예외처리

} finally {if (stmt != null) { try {stmt.close();}catch(SQLException e){}}// end ifif (con != null) { try {con.close();}catch(SQLException e){}}// end if

}// end try-catch-finallyreturn result;

update()

한국 스프링 사용자 모임 (http://ksug.org) 16

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementstmt = con.prepareStatement( " insert into LECTURE values(?, ?, ?, ?, ?)“);

// binding sql parameterstmt.setString(1, name);//...

// execute Queryresult = stmt.executeUpdate();

} catch (SQLException exception) {// 예외처리

} finally {if (stmt != null) { try {stmt.close();}catch(SQLException e){}}// end ifif (con != null) { try {con.close();}catch(SQLException e){}}// end if

}// end try-catch-finallyreturn result;

insert()

한국 스프링 사용자 모임 (http://ksug.org) 17

1.3 Refactoring with Strategy pattern• Strategy pattern 이 적용된 Template.update()

한국 스프링 사용자 모임 (http://ksug.org) 18

1.3 Refactoring with Strategy pattern• 변경되는 부분과 그렇지 않은 부분 식별하기 , 각각

– querying sql 실행try {

// get DB connectioncon = getConnection();

// create Statementrs = con.prepareStatement( “select * from LECTURE where ID=?“);

// binding sql parameterstmt.setInt(1, id);

// execute Queryrs = stmt.executeQuery();

//extract resultwhile (rs.next()) {

result = new Lecture();Result.setName(rs.getString(2));// extracting...

}

} catch (SQLException exception) {// 예외처리

} finally {// 자원 반환 처리

}return result;

try {// get DB connectioncon = getConnection();

// create Statementrs = con.prepareStatement( “select * from LECTURE“);

// binding sql parameter

// execute Queryrs = stmt.executeQuery();

//extract resultwhile (rs.next()) {

lecture = new Lecture();Result.setName(rs.getString(2));// extracting...

result.add(lecture);}

} catch (SQLException exception) {// 예외처리

} finally {// 자원 반환 처리

}return result;

get() getall()

한국 스프링 사용자 모임 (http://ksug.org) 19

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementrs = con.prepareStatement( “select * from LECTURE where ID=?“);

// binding sql parameterstmt.setInt(1, id);

// execute Queryrs = stmt.executeQuery();

//extract resultwhile (rs.next()) {

result = new Lecture();Result.setName(rs.getString(2));// extracting...

}

} catch (SQLException exception) {// 예외처리

} finally {// 자원 반환 처리

}return result;

get()

메소드 인자로 빼냄

콜백 메소드로 구현

공통 메소드로 추출

getall()

한국 스프링 사용자 모임 (http://ksug.org) 20

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementrs = con.prepareStatement( “select * from LECTURE where ID=?“);

// binding sql parameterstmt.setInt(1, id);

// execute Queryrs = stmt.executeQuery();

//extract resultwhile (rs.next()) {

result = new Lecture();Result.setName(rs.getString(2));// extracting...

}

} catch (SQLException exception) {// 예외처리

} finally {// 자원 반환 처리

}return result;

get()getall()

한국 스프링 사용자 모임 (http://ksug.org) 21

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementrs = con.prepareStatement( “select * from LECTURE where ID=?“);

// binding sql parameterstmt.setInt(1, id);

// execute Queryrs = stmt.executeQuery();

//extract resultwhile (rs.next()) {

result = new Lecture();Result.setName(rs.getString(2));// extracting...

}

} catch (SQLException exception) {// 예외처리

} finally {// 자원 반환 처리

}return result;

getall()

한국 스프링 사용자 모임 (http://ksug.org) 22

1.3 Refactoring with Strategy pattern

try {// get DB connectioncon = getConnection();

// create Statementrs = con.prepareStatement( “select * from LECTURE where ID=?“);

// binding sql parameterstmt.setInt(1, id);

// execute Queryrs = stmt.executeQuery();

//extract resultwhile (rs.next()) {

result = new Lecture();Result.setName(rs.getString(2));// extracting...

}

} catch (SQLException exception) {// 예외처리

} finally {// 자원 반환 처리

}return result;

get()

한국 스프링 사용자 모임 (http://ksug.org) 23

1.3 Refactoring with Strategy pattern• Strategy pattern 이 적용된 Template.query()

한국 스프링 사용자 모임 (http://ksug.org) 24

1.3 Refactoring with Strategy pattern• Refactoring 1.

– 결과 값의 타입은 ?– ResultSet 처리

• 동일한 DTO 인 경우 , 거의 동일하게 ResultSet 에서 값을 빼내는 코드가 반복됨

return (Lecture) template.query("select * from LECTURE where ID=?",...}, new ResultSetExtractor() {

public Object extractResult(ResultSet rs)throws SQLException {

// extract result to Single ObjectLecture result = new Lecture();

while (rs.next()) {result.setId(rs.getInt(1));result.setName(rs.getString(2));result.setSpeaker(rs.getString(3));

}

return result;

}});

return (List<Lecture>) template.query("select * from LECTURE",...}, new ResultSetExtractor() {

public Object extractResult(ResultSet rs)throws SQLException {

// extract result to Collection ObjectList<Lecture> result =

new ArrayList<Lecture>();

while (rs.next()) {Lecture lecture = new Lecture();lecture.setId(rs.getInt(1));lecture.setName(rs.getString(2));lecture.setSpeaker(rs.getString(3));

result.add(lecture);}return result;

}});

get() getall()

한국 스프링 사용자 모임 (http://ksug.org) 25

1.3 Refactoring with Strategy pattern

return (Lecture) template.query("select * from LECTURE where ID=?",...}, new ResultSetExtractor() {

public Object extractResult(ResultSet rs)throws SQLException {

// extract result to Single ObjectLecture result = new Lecture();

while (rs.next()) {result.setId(rs.getInt(1));result.setName(rs.getString(2));result.setSpeaker(rs.getString(3));

}

return result;

}});

get()

콜백 메소드로 구현

API 로 구분

한국 스프링 사용자 모임 (http://ksug.org) 26

1.3 Refactoring with Strategy pattern

return (Lecture) template.query("select * from LECTURE where ID=?",...}, new ResultSetExtractor() {

public Object extractResult(ResultSet rs)throws SQLException {

// extract result to Single ObjectLecture result = new Lecture();

while (rs.next()) {result.setId(rs.getInt(1));result.setName(rs.getString(2));result.setSpeaker(rs.getString(3));

}

return result;

}});

get()

한국 스프링 사용자 모임 (http://ksug.org) 27

1.3 Refactoring with Strategy pattern

return (Lecture) template.query("select * from LECTURE where ID=?",...}, new ResultSetExtractor() {

public Object extractResult(ResultSet rs)throws SQLException {

// extract result to Single ObjectLecture result = new Lecture();

while (rs.next()) {result.setId(rs.getInt(1));result.setName(rs.getString(2));result.setSpeaker(rs.getString(3));

}

return result;

}});

get()

한국 스프링 사용자 모임 (http://ksug.org) 28

1.3 Refactoring with Strategy pattern• Refactoring 2.

– 여전히 Template 의 query() 와 update() 에서 JDBC API가 중복되어 사용된다 !

한국 스프링 사용자 모임 (http://ksug.org) 29

1.3 Refactoring with Strategy pattern• Refactoring 2. 결과

한국 스프링 사용자 모임 (http://ksug.org) 30

1.3 Refactoring with Strategy pattern• 콜백 인터페이스가 적용된 공통 메소드

한국 스프링 사용자 모임 (http://ksug.org) 31

1.4 Summary• 구현한 템플릿 클래스와 인터페이스

한국 스프링 사용자 모임 (http://ksug.org) 32

1.4 Summary• JdbcTemplate 도입된 이후의 효과

– JDBC workflow 의 흐름 진행 주체• DAO JdbcTemplate

– DAO 의 역할 충실화• SQL, 파라미터 제공 or 결과 매핑• 이 외의 다른 역할은 JdbcTemplate 를 비롯한 각 담당자에게 위임

한국 스프링 사용자 모임 (http://ksug.org) 33

2. SPRING JDBCTEMPLATE

한국 스프링 사용자 모임 (http://ksug.org) 34

2.1 Best Practice of JDBC Strategy• Spring JDBC core package’s Central class• Jdbc UseCase Best Practice• Collaborate with Various Callback Interface

Strategy pattern!• Convenience DA operation

"This is a special case of the Strategy design pattern. It appears different because the interface involved are so simple"

한국 스프링 사용자 모임 (http://ksug.org) 35

2.1 Best Practice of JDBC Strategy• JdbcTemplate with Strategy pattern

DAO

Template

CallbackInterface

implementation참조 : wiki[2]

한국 스프링 사용자 모임 (http://ksug.org) 36

2.1 Best Practice of JDBC Strategy

Jdbc-based DAO Spring-based DAODriverManager / DataSource

DataSource

Statement / PreparedStatement / CallableStatement

JdbcTemplate / Callback interface

ResultSet POJO / POJO’s collection

한국 스프링 사용자 모임 (http://ksug.org) 37

2.1 Best Practice of JDBC Strategy

Task Spring You

Connection(DataSource) management

Provide SQL

Statement management

Parameter Declaration

Provide parameter value

ResultSet management

Row Data Retrieval

Transaction management

Exception handling

한국 스프링 사용자 모임 (http://ksug.org) 38

2.1 Best Practice of JDBC Strategy• Convenience, but powerful Jdbc Template

– Resource management• DataSourceUtils

– Integrated with Transaction management• Spring-tx (non-invasive)

한국 스프링 사용자 모임 (http://ksug.org) 39

2.1 Best Practice of JDBC Strategy• Convenience, but powerful JdbcTemplate

– Consistent exception management• 예외 발생 시 처리 기준

– 에러 코드 (error code), 에러 상태 (error state) 예외 종류 (type of Exception)

• Check exception Unchecked exception• SQLExceptionTranslator

한국 스프링 사용자 모임 (http://ksug.org) 40

2.1 Best Practice of JDBC Strategy• Convenience, but powerful JdbcTemplate

– Logging for SQL inform. (DEBUG level)– Various Template

• JdbcTemplate• NamedParameterJdbcTemplate• SimpleJdbcTemplate

– Convenience DA operation• named parameter• Auto-detect column by Jdbc Driver• Easily using Batch, LOB

한국 스프링 사용자 모임 (http://ksug.org) 41

2.1 Best Practice of JDBC Strategy• JdbcTemplate 구성 방법

– DataSource(or Connection Pool) 가 쓰레드 안전하다면 , JdbcTemplate 도 쓰레드 안전

private JdbcTemplate template;

public void setTemplate(DataSource dataSource) {this.template = new JdbcTemplate(dataSource);

}

<bean id="lectureDao" class="org.springframework.lecture.jdbc.dao.JdbcLectureDao">

<property name="template" ref="dataSource" /></bean>

private JdbcTemplate template;

public void setTemplate(JdbcTemplate template) {this.template = template;

}

<bean id="lectureDao" class="org.springframework.lecture.jdbc.dao.JdbcLectureDao">

<property name="template" ref="jdbcTemplate" /></bean>

한국 스프링 사용자 모임 (http://ksug.org) 42

2.2 SIMPLIFY JDBC OPERATION

한국 스프링 사용자 모임 (http://ksug.org) 43

2.2 Simplify JDBC operation• SimpleJdbc* 활용하기

– SimpleJdbcTemplate• Wrapper around classic JdbcTemplate

class(getJdbcOperations())• Java-5-based convenience wrapper for the classic Spring

JdbcTemplate• Varargs, Generic, Autoboxing, Unboxing...

한국 스프링 사용자 모임 (http://ksug.org) 44

2.2 Simplify JDBC operation• SimpleJdbc* 활용하기

– SimpleJdbcInsert• Simplify Insert behavior• JdbcTemplate + DatabaseMetaData• ‘fluid’ interface style

한국 스프링 사용자 모임 (http://ksug.org) 45

2.2 Simplify JDBC operation• SimpleJdbc* 활용하기

– SimpleJdbcCall• multi-threaded, reusable object representing a call to stored

procedure or a stored function

– SimpleJdbcTestUtils

한국 스프링 사용자 모임 (http://ksug.org) 46

2.2 Simplify JDBC operation• The Pareto Principle in action

– JdbcTemplate+callback interface by Reflection = 80– SqlQuery + inheritance by explicit parameter

mapping =20

한국 스프링 사용자 모임 (http://ksug.org) 47

2.2 Simplify JDBC operation• RowMapper(with ResultSetExtractor)

– per-row basis– Stateless & reusable– Ideal choice of row-mapping logic

• ResultSetExtractor– per-resultSet basis– Stateless & reusable, if not access stateful resource

한국 스프링 사용자 모임 (http://ksug.org) 48

2.2 Simplify JDBC operation• SqlQuery

– by Inheritance– Reusable, threadsafe class– Encapsulate SQL– MappingSqlQuery & UpdatableSqlQuery– Using meaningful method name

한국 스프링 사용자 모임 (http://ksug.org) 49

2.2 Simplify JDBC operation• RowCallbackHandler

– Stateful– public void processRow(ResultSet rs) throws

SQLException

한국 스프링 사용자 모임 (http://ksug.org) 50

2.2 Simplify JDBC operation• DataFieldMaxValueIncrementer 활용하기

– Sequence-based• Oracle, PostgreSQL, DB2(plain, mainframe), HSQL, H2

– Column-based• MySQL, MS-SqlServer, Sybase, Hsql, Derby

• BeanProperty* 활용하기– (Parameterized)BeanPropertyRowMapper– BeanPropertySqlParameterSource

한국 스프링 사용자 모임 (http://ksug.org) 51

Reference• wiki[1]:

http://en.wikipedia.org/wiki/Image:Strategy_Pattern_Diagram_ZP.svg

• wiki[2]: http://en.wikipedia.org/wiki/Image:Strategy_pattern_in_LePUS3.gif

• Tomas[1]: JDBC Development with the Spring Framework

• Spring reference• Spring API• J2EE Design and Development• J2EE without EJB

한국 스프링 사용자 모임 (http://ksug.org) 52

감사합니다 .

top related