[Boostcourse] 풀스택/웹 프로그래밍(풀스택)

Spring JDBC 실습3 : SelectAll { DTO, DAO, NamedParameterJdbcTemplate, RowMapper, ConnectionPool & DataSource }

Ben의 프로그램 2023. 7. 26. 21:22
728x90
수업목표
지난 예제에서는 접속을 하는 부분까지 작성을 하였는데요. 이번에는 Select 하는 부분까지 작성을 해보겠습니다.

 

Select 하기 위한 클래스들 생각해보기
Select 하기 위해서는 어떤 클래스가 필요할지 생각을 하고 진행을 하겠습니다. 

데이터를 select 하기 위해서는 데이터의 교환이 이루어지게 됩니다. 그때 DTO(Data Transfer Object) 가 필요합니다. 그 다음에 우리는 쿼리문이 필요할텐데요. 쿼리문을 가지고 있는 RoleDaoSqls 라는 클래스도 하나 만들겠습니다. 그리고 마지막으로 데이터에 실제로 Access 할 수 있는 DAO(Data Access Object) 객체인 RoleDao 가 필요합니다. NamedParameterJdbcTemplateSimpleJdbcInsert 객체들은 Spring JDBC 가 제공해주는 객체들입니다. 이제 객체들을 작성을 할텐데요. 개발자가 실제로 작성하는 객체들은 어떤 것이고 Spring 이 작성하는 객체들은 어떤 것들인지 생각하면서 진행하는 것이 좋겠습니다.

 

DTO 만들기
이제 DTO 부터 하나씩 만들어보겠습니다. 

DTO 도 따로 패키지를 구별을 해서 만들어주는 것이 좋겠습니다. 우리는 Role 이라는 간단한 DTO 를 생성할 겁니다. roleId 와 description 필드를 갖고 있으며 setter 와 getter 메서드를 갖고 있구요. 데이터 확인할 때 편리함을 위해서 toString( ) 을 갖게 되었습니다. 

 

RoleDaoSqls 클래스 만들기
DAO 패키지를 만든 다음에 클래스를 이어서 만들겠습니다.

이 클래스에다가 사용할 SQL 들을 상수로 작성하면 됩니다. 상수를 작성할 때 상수명은 모두 대문자로 작성하고 카멜표기법 대신 _ 언더바를 사용합니다. 이렇게 SQL 을 갖고 있는 객체도 생성하였습니다. 

 

RoleDao 클래스 만들기 (ConnectionPool 컨트롤하는 DataSource 를 통해 NamedParameterJdbcTemplate 생성)
이번에는 실제로 Access 할 수 있는 객체를 만들겠습니다. 

Access 를 실제로 하는 객체를 DAO(Database Access Object)라고 했었습니다. Role 이라는 테이블에 접근할 거니까 RoleDao 클래스를 생성합니다. 


이 클래스는 Spring Container 가 읽어들여서 사용을 하게 되는데요. 이것을 지정해주기 위해서 Annotation 을 사용한다고 했었습니다. @Component, @Service 등의 어노테이션을 사용하면 Bean 으로 등록된다고 했었습니다. 그 중에서 RoleDao 는 DAO 객체로서 저장소의 역할을 한다는 의미로 @Repository 라는 어노테이션을 사용합니다. @Repository 는 이 객체에 대해서 '나는 Repository야' 라고 알려주는 Annotation 이라고 이해를 하시면 좋을 것 같습니다. 

이 RoleDao 는 실제로 실행을 할 때 NamedParameterJdbcTemplate 과 SimpleJdbcInsert 객체를 이용하는 것을 볼 수 있는데요. 이 객체들은 Spring JDBC 가 JDBC 사용을 편리하게 하기 위해서 이미 구현해 놓은 객체들입니다. 현재 우리는 Select All 을 할 예정인데요. NamedParameterJdbcTemplate 안의 메서드들을 보면 query( ), queryForObject( ), update( ) 메서드들이 있는 것을 확인할 수 있습니다. 이 객체들을 사용하려면 선언을 해야 하는데요. 코드를 작성해보겠습니다. 

Spring JDBC 에서 가장 중요한 객체가 SpringJdbcTemplate 이라고 했었는데요. JDBC Template 은 바인딩할 때 물음표(?)를 사용했었습니다. 물음표를 사용하게 되면 SQL 문자열만 보면 어떤 값이 매핑되는지 알아보기 힘든 문제들이 있었습니다. 이런 문제를 해결하기 위해서 NamedParameterJdbcTemplate 이 사용이 되었습니다. NamedParameterJdbcTemplate 은 이름을 사용해서 바인딩하거나 결과값을 가져올 때 사용할 수 있습니다. 그래서 우리는 이 객체를 사용합니다. 다음에 생성자 부분을 살펴보면 DataSource 를 매개변수로 받고 있는데요. Spring 버전 3.4 부터는 ComponentScan 으로 객체를 찾았을 때 기본 생성자가 없다면 자동으로 객체를 주입을 해주는데요.

이 dataSource 의 Bean 을 주입받은 것을 매개변수로 사용하여서 NamedParameterJdbcTemplate 객체를 생성하게 됩니다. 

그 다음은 이제 실제로 우리가 수행하려는 Selct All 역할을 수행하는 메서드를 만들겁니다. 이 메서드는 Role 을 여러건 받아올 거니까 Role 을 List 로 받아오면 되겠죠

실제로 Role 객체로 한건 한건 데이터를 받아서 List 에 저장하는 코드는 반복되는 코드이므로 개발자가 작성하지 않고 NamedParameterJdbcTemplate 에 구현된 코드를 사용하게 됩니다. jdbc.query( ) 메서드를 통해서 SelectAll 메서드를 구현할 것인데요. jdbc.query( ) 메서드의 첫 번째 인자는 sql니다.


이 sql 은 우리가 RoleDaoSqls 라는 객체에 구현을 해놓았는데요. 이 상수를 사용하기 위해서 import static 을 사용합니다. 인스턴스 생성 없이 멤버변수를 사용할 수 있게 됩니다. 

query( )  메서드의 두 번째 매개변수로는 비어있는 Map 객체를 선언하면 되는데요. Collections.emptyMap( ) 를 해주시면 됩니다(저의 경우 query( ) 메서드가 해당 코드를 인식하지 못하는 문제가 발생해서 EmptySqlParameterSource.INSTANCE 를 사용하였습니다.). 두 번째 매개변수가 하는 역할은 바인딩할 값들이 있을 때 값을 전달하는 역할을 수행하게 됩니다. 
query( ) 메서드의 세 번째 매개변수로는 위에서 만들어놓았던 rowMapper 를 사용하면 됩니다. 세 번째 매개변수가 하는 일은 Select 한 건 한 건을 DTO 에 저장하는 목적으로 사용을 하게 됩니다. BeanPropertyRowMapper 객체를 활용하여 Row 의 데이터를 자동으로 DTO 에 담아주게 됩니다. 
결론적으로 jdbc.query( ) 메서드는 DataBase 에서 Row 를 한 건 한 건 읽어 DTO 에 담은 다음 DTO 를 List 에 담아서 반환해줍니다.

한편 DBMS 에서는 단어와 단어를 구분할 때 _ 언더바를 사용하고 자바에서는 카멜케이스를 사용하는데요. DBMS 는 대소문자를 구분하지 않기 때문입니다. 이렇게 둘의 이름이 달라서 오류가 발생할 수 있음이 자명해 보이죠. 그런데 BeanPropertyRowMapper 는 놀랍게도 DBMS와 Java 의 이름 규칙을 자동으로 맞추어주는 아주 편리한 기능을 가지고 있습니다. 

 

ApplicationConfig 수정 : @ComponentScan
그 다음에는 우리가 Bean 을 등록하는 방법으로 Annotation 을 활용했었는데요. ApplicationConfig 에다가 설정을 하나 해주어야 합니다.

'나 ConponentScan 으로 읽어낼거야' 라는 것을 설정을 해주어야 합니다. 그래야 이 설정 파일을 읽어낼 때 약속된 어노테이션들이 있는 객체들을 찾아내서 진행을 하게 됩니다. @ComponentScan 을 사용할 때는 base 패키지 주소를 지정을 해서 사용해야 한다고 했었습니다. 지난 시간에 @ComponentScan base패키지 주소를 바로 입력했었는데요. 위의 방식대로 basePackages = { } 방식을 활용하면 basePackage 주소를 여러 개 나열해줄 수 있습니다.

 

Test 클래스 생성 및 실행
필요한 코드는 모두 작성했는데요. 이번에는 실제 Test 코드를 작성하겠습니다. main 패키지에 SelectAllTest 라는 클래스 파일을 만들겠습니다. 

매번 반복되는 코드인데요. AnnotationConfigApplicationContext 를 통해서 ApplicationContext 객체를 우선 생성했구요. ApplicationContext 객체의 getBean( ) 메서드를 통해서 roleDao 객체를 생성했습니다. 그리고 roleDao 객체의 selectAll( ) 메서드를 통해서 데이터베이스의 담긴 모든 데이터들의 정보를 list 에 담았습니다.

실행을 해보았더니 정상적으로 실행이 되고 있는 것을 확인할 수 있습니다. 

 

출처 : boostcourse 웹 프로그래밍(풀스택) 
https://www.boostcourse.org/web316/lecture/20655?isDesc=false