공부/Spring

[Spring] CHAPTER 04 데이터 엑세스층의 설계와 구현

JangGiraffe 2016. 2. 24. 00:14

이 책을 홍보하는건 아니지만 쭉 읽어가다 궁금한 부분이 생기면 '다음장에 자세히 설명되있다' 라든지 비슷한 문구들이 있어 믿는구석이 생겨 그냥 읽어나가는데 큰 벽이나 문제점이 생기지 않는듯하고 또 중간중간에 호기심을 자극하는 여러 요소들이 있어 책의 내요에 대한 흥미를 떨어뜨리지 않게 도와주는것 같다.ㅋㅋㅋ

----------------------------------------------------------------------------------------------------------------------------------------------

 

4장 데이터 액세스층의 설계와 구현

 

 데이터 액세스층의 역할은 앞서 말했듯이 DB의 접속과 SQL 발행같은 데이터 액세스 처리를 (가장 중요한 역할을 하는)비즈니스 로직층으로부터 분리하는 것이다.

덕분에 비즈니스로직층은 데이터 엑세스처리에 신경쓰지 않고 기술할 수 있으므로 소스코드가 확실히 간결해지고 그렇기 때문에 유지관리가 쉬워진다.

 

DAO 패턴?

 데이터 액세스(DB접속과 SQL발행과 같은 일)의 처리에 특화된 오브젝트를 일반적으로 DAO(Data Access object)라고 한다.


*CRUD : Create,Read,Update,Delete의 머리글자를 이어붙인 것)

DAO가 구현하는 메소드는 단순한 CRUD를 갖춘 형태가 된다.

DAO가 구현하는 클래스는 테이블 별로 만들어지는 일이 많다. (UserDao , BankDao 등등 과 같이)

부품화하고자 하는 인터페이스를 준비해 개발 효율이나 유연성을 높힌다.

 

자바의 데이터 액세스 기술과 스프링의 기능

 자바에는 JDBC,MyBatis 등등의 다양한 기술들이 있고 스프링은 이 기술 중 5가지(JDBC,Hibernate,JPA,MyBatis,JDO) 기술들을 더욱 사용하기 쉽게 만들어주는 역할을 한다.

어떤식으로 쉽게 만들어 주냐면

1) 데이터 액세스 처리를 간결하게 기술할 수 있다.

2) 스프링이 제공하는 범용적, 체계적 데이터 액세스 예외를 이용할 수 있다.

3) 스프링의 트랜잭션 기능을 이용할 수 있다.

바로 밑에서 이 1~3번에대한 방법을 JDBC의 문제점과 함께 설명할꺼임

(이책에서는 JDBC위주로 설명한다고 함. 그러니 이 글도 JDBC위주로..쓰이겠네요 마이바티스, 하이버네이트? 이런것들은 10~13장에서 소개한데)

 

JDBC를 직접 사용했을 때의 문제점

1)간단한 select문 조차 작성시 소스코드가 길어진다. (과장해서 엄청김)

2)Connection,PreparedStatement를 얻은 후 연결 해제 처리를 하지 않으면 DB리소스 고갈이나 메모리누수의 원인이 되며 최악의 경우 시스템 정지

3)DB제품마다 오류코드가 다르므로 SQLException 사용시 제품이 바뀔때 마다 수정이 필요함.

4)예외처리시 Catch구문이 필수로 필요하다.

 

>>스프링JDBC를 이용하면 해결이 가능하다.

1) Template 클래스를 사용하 소스코드를 단순하게 한다.

스프링JDBC의 두 개의 클래스 JdbcTemplate 클래스와 NamedParameterJdbcTemplate 클래스가 있는데. 이 둘을 템플릿 클래스라고 부른다. JDBC로 구현했을 때 긴 코드부분을 단순하게 구현해 주는 것이다.

[1] template클래스 Bean 등록 : 템플릿 클래스를 Bean 정의파일에 등록할 필요가 있다.

 <bean class="org.springframework.jdbc.core.JdbcTemplate">
   <constructor-arg ref="dataSource"/>
</bean>

<bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
   <constructor-arg ref="dataSource"/>
</bean>

>>두가지 템플릿 클래스의 Bean 등록 방법.

각각 생성자에서 데이터 소스를 인젝션한다. (템플릿클래스에 Setter 메소드가 없기때문이다)

그 다음은 DAO에 인젝션해야 한다. 템플릿클래스의 오브젝트를 저장할 필드를 준비해서 @Autowired를 지정하면템플릿 클래스의 Bean이 인젝션된다.(Bean정의파일을 사용해서 인젝션 해도 된다)

 

Select문 - 도메인으로 변환하지 않을 때

(도메인으로 변환하지 않을 때란 예를 들어 레코드의 수를 조회할 때 한 레코드 안의 특정 칼럼처럼 단순한 값을 가져올 때를 가리킨데.. 후)

- 단순한 값 가져오기 : queryForInt , queryForLong

ex) int count = jdbcTemplate.queryForInt("SELECT COUNT(*) FROM PET");

- 문자열, 날짜형 가져오기 : queryForObject

ex) Date birthDate = jdbcTemplate.queryForObject("SELECT BIRTH_DATE FROM PET WHERE PET_ID=?",Date.class,id);

- 한 레코드 가져오기 : queryForMap

Map<String,Object> pet = jdbcTemplate.queryForMap("SELECT * FROM PET WHERE PET_ID=?",id);

- 한 리스트 가져오기 - queryForList

List<Map<String,Object>> petList = jdbcTemplate.queryForList("SELECT * FROM PET WHERE OWNER_NAME=?",ownerName);

 

Select문 - 도메인으로 변환할 때

queryForObject메소드와 qeury메소드를 사용한다.

--------

- 한 레코드의 도메인을 가져올 때 : queryForObject

Pet pet jdbcTemplate.queryForObejct("SELECT * FROM PET WHERE PET_ID=?",new RowMapper<PET>() {

 public Pet mapRow(ResultSet rs, int rowNum) throws SQLException{

Pet p = new Pet();

p.setPetId(rs.getInt("PET_ID"));

p.setPetName(rs.getString("PET_NAME"));

return p;

}}

,id);

 첫번째 인수는 select문, 세번째 인수는 select문의 파라미터, 두번째 인수는 도메인으로 변환 처리하는 클래스의 오브젝트를 건내주고 있다. 두번째 인수에서 처리코드 내부에 메소드의 정의가 들어간 기술방식은. 클래스를 정의하는거라는데 그자리에서만 쓰는 일회용 구현 클래스. 익명클래스라고 부른다.

 

그림 . mapRow가 호출되는 시점↓

[그림 설명] DAO가 RowMapper 오브젝트를 queryForObject 메소드의 인수로 넘기면 JdbcTemplate은 커넥션을 획득하고 SQL을 발행해서 ResultSet을 얻는다. ResultSet을 인수로 해서 mapRow를 호출한다. mapRow 내부에서 ResultSet이 도메인으로 변환되고, 변환된 오브젝트가 queryForObject 메소드의 반환값으로 돌아오는 것이다. 와우 ㅋㅋ

--------

- 여러 레코드의 도메인을 가져올 때 : query

queryForObejct와 같은방식이므로 생략. (ㅈㅅ)

--------

 

Insert, Update, Delete문

메소드가 다양했던 SELECT문과 달리 INSERT,UPDATE,DELETE문 모두 update메서드만 사용한다. 모두 갱신 계통의 SQL이기 때문이다. 메소드명인 update와 SQL의 UPDATE문은 다른개념이므로 혼동하지 말자.

jdbcTemplate.update("INSERT INTO PET(PET_ID,PET_NAME) VALUES(?,?)" , pet.getPetId(),pet.getPetName()); 

jdbcTemplate.update("UPDATE PET SET PET_NAME=?,OWNER_NAME=?",pet.getPetName(),pet.getOwnerName()); 

jdbcTemplate.update("DELETE FROM PET WHERE PET_ID=?",pet.getPetId());

첫 번째 인수로 SQL문을, 두 번째 인수 이후로 파라미터 값을 지정하면 된당. 참쉽넹ㅋㅋ

 

NamedParameterJdbcTemplate

플레이스홀더(?마크..)를 사용하면 SQL문의 파라미터 값이 많다면 혼란스러워지는데, NamedParameterJdbcTemplate를 사용하면 좋다.

파라미터 순서가 어긋날 위험성을 없앨 수 있다.

 예제코드)

npJdbcTempate.update("INSERT INTO (PET_ID,PET_NAME) VALUES(:PET_ID,:PET_NAME)",

                                  new MapSqlParameterSOurce()

                                  .addValue("PET_ID",pet.getPetId())

                                  .addValue("PET_NAME",pet.getPetName())

);

 

batchUpdate 메소드

배치업데이트 메소드는 많은 양의 레코드를 한 번에 갱신하기 위한 메소드다. update메소드로 한번한번 해서 여러번하는것과 배치업데이트를 사용함은 성능차이가 많이 나기 때문에 이걸 이용하는게 좋대.

List배열에 레코드들을 넣고 이 변수를 배치업데이트 함수에 인자로 사용하면 됨.

 

범용데이터 액세스 예외

여러 데이터 액세스 기술의 독자적 예외를 스프링이 범용 데이터베이스 예외로 변환해줌으로써 개발자가 SQLException을 분석할 필요가 없게 해주며 DB제품간의 오류코드 차이도 스프링이 커버해준다.

Template 클래스를 사용하면 자동 적용되기 때문에 신경쓸 필요 없는듯.

(?) 범용 데이터 액세스 예외는 실행시 예외가 아니므로 대처가 가능한 예외만 대처가 가능한 장소에서 catch하면 되는것 (catch가 필수가 아님을 뜻함)

-->>DAO에서 대처해야만 하는 예외는 기본적으로 없으므로 던지는게 좋음. 예를 들어 가져와야 할 데이터를 가져오지 못했을 때 EmptyResultDataAccessException이 던져졌다고 하면. 서비스가 예외를 catch해서 다른 테이블에서 데이터를 가져오는 것으로 대처하면 된다. 데드락이 발생했을 때는 DeadlockLoserDataAccessException이 던져지며 컨트롤러가 catch해서 브라우저에 10초 후에 다시 접속해주세요 라는 메시지를 표시해서 대처할 수도 있다 라고 하는데 아직 잘 이해가 안간다..;;ㅋ

 

데이터소스

이거는 스프링 JDBC에 특화한 이야기가 아니라 스프링이 제공하는 데이터 액세스 기능 전체에 공통된 이야기입니다.

데이터소스는 데이터소스와 접속오브젝트 Connection 오브젝트의 팩토리라고 할 수 있다.

커넥션 오브젝트의 생애주기는 데이터 소스에 맡겨져 있고 일반 업무 애플리케이션에서는 커넥션풀에 의해 커넥션 오브젝트를 돌려쓰는 구조로 되어 있다. 그 이유는 제한없이 connection 오브젝트가 만들어져 DB의 리소스가 고갈되는 것을 막거나 커넥션오브젝트의 생성, 해체시의 부하를 막기 위해서이다.

 

스프링에서 데이터소스를 이용하는 방법은 우선 DataSource를 Bean정의파일로 정의한 다음 개발자가 작성한 Bean과 스프링이 제공하는 Bean(스프링 JDBC의 Template등)에 인젝션해 이용한다.

JDBC 드라이버 클래스명과 URL등 접속정보는 별도의 프로퍼티 파일을 준비하는게 좋다.

데이터소스의 Bean정의방법은 크게 3가지가 있다.

1) 스프링제공 DataSource(singleconnectionDataSource,DrivenManagerDataSource) 개인적으로 놀라웠던 점은(;;) 두 클래스 모두 테스트용도로 만들어져 있으며 커넥션풀을 지원하지 않는다는 점?

2) 서드파티 제공 DataSource

3) 애플리케이션 서버 제공 DataSource

>>2,3번의경우 이해가 부족해 나중에 포스팅하기로..

트랜잭션 처리는 다음장에서 계속.

 

 

 

 

반응형