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

JDBC 실습 : 한 건 Select하기 { Connection, Statement, ResultSet 객체 }

Ben의 프로그램 2023. 7. 21. 22:26
728x90
Maven 프로젝트 생성
JDBC 실습을 위한 Maven 프로젝트를 하나 먼저 생성하고 진행하겠습니다. 

 

Maven 프로젝트 초기 설정
Maven 프로젝트를 생성하면 pom.xml 에 해주어야 하는 작업이 있었습니다.
pom.xml 에 jdk 를 사용하기 위해서 플러그인을 추가했구요. jdbc 를 사용하기 위한 드라이버를 dependency 부분에 추가해주었습니다. 이렇게 pom.xml 을 수정한 다음에는 반드시 maven project 를 새로고침 해주어야 합니다. 

 

 

JDBC 객체 생성
[ DB 접속 및 사용할 테이블 확인 ]

JDBC 는 데이터베이스에 데이터를 쓰고 읽는 역할을 수행합
니다. 즉 데이터베이스에서 읽고 쓰는 객체를 만들어 주어야 합니다. 우선 DB에 접속을 해주겠습니다. 

그 다음 role 이라는 테이블을 읽고 쓸 예정인데요. role 테이블의 상태를 우선 확인해 보겠습니다. 


[ dto 패키지 생성 & Role 테이블을 읽고 쓸 Role 클래스 파일 생성 ]

이번에는 패키지를 하나 만들겁니다. 

dto 라는 패키지를 만들건데요. 의미를 가진 단어인데 다음 챕터에서 조금 더 자세하게 배울 예정입니다. dto 패키지에 Role 이라는 클래스 파일을 하나 만들었습니다. Role 이라는 테이블에는 2개의 컬럼이 있었죠. 컬럼을 담을 변수를 생성하겠습니다. 

여기서 유의하여 보아야 하는 점은 우선 변수명인데요. DB에서는 언더바 _ 를 사용하여 변수명을 생성하지만 자바에서는 카멜표기법을 사용하기 때문에 이런 형식을 지켜서 작성을 해주어야 합니다. 또한 자료형도 자바에서는 Integer 와 String 을 사용한 것을 볼 수 있습니다.

이 변수들에서 데이터를 넣고 쓰기를 해야 합니다. private 으로 선언된 변수를 읽고 쓰기 위해서 getter setter 메서드를 추가해줍니다.

이런 객체들은 안에 들어있는 값들이 중요한데요. 객체 안에 들어 있는 값을 편하게 꺼내 쓸 수 있도록 toString( ) 을 재정의해주겠습니다.

객체를 생성할 때 편하게 생성하기 위해서 생성자도 만들었습니다. 


[ dao 패키지 생성 & RoleDao 클래스 파일 생성 ]

이번에는 Role 객체를 통해 입력, 조회, 수정, 삭제 등의 기능을 갖는 RoleDao 객체를 만들고자 합니다. dto 와 dao 에 대해서는 다음 파트에서 조금 더 깊게 공부하겠습니다. 

데이터를 한 건 가져오는 것을 먼저 작성해보겠습니다. 한 건을 가져온다는 것은 한 데이터를 담아낼 객체가 필요하다는 것을 의미합니다. 그리고 우리는 그러한 역할을 수행할 객체로 Role 을 생성했었습니다. 그러니까 Role 을 return 하는 getRole 메서드를 작성하겠습니다. getRole 메서드는 가져올 데이터를 특정하기위한 인자로 roleId 를 갖습니다.

앞서서 JDBC 의 단계별 동작을 배웠었는데요. 그 부분들을 선언을 해줄 겁니다. 첫 번째는 연결을 맺을 수 있는 객체를 생성합니다. 

두 번째는 명령을 선언할 객체인 Statement 객체를 하나 생성합니다. 

세 번째는 결과값을 담아낼 객체인 ResultSet 객체를 하나 생성합니다. 

그 다음에는 예외처리를 꼭 해주어야 합니다. 지금처럼 DB에 연결하여 데이터를 통신하는 부분에서는 예외 상황들이 굉장히 많을 것 같죠? 중간에 연결이 끊어지거나 등등 엄청 많은 예외 상황들이 발생할 겁니다. try catch 구문을 이용해서 예외를 처리해 줄 겁니다. 

DB 에 연결해서 데이터를 가져오기 위해서 생성했던 객체들이 있는데요. 이 객체들을 닫아주는 것이 엄청 중요합니다. 닫아주지 않으면 엄청 많은 예외 상황들이 발생하거든요. 그런데 일을 하다보면 실수로 까먹거든요. 그래서 항상 처음에 finally 구문을 통해서 객체를 닫아주는 것을 먼저 작성합니다. 닫아주는 코드는 각 객체마다 close 메서드를 실행시켜주어야 합니다. 그런데, 이 close( ) 메서드 자체도 예외를 처리해주어야 하는 메서드입니다.

그런데, 여기서 한가지 더 생각해야 하는 점이 있습니다. 

접속을 하다가 예외가 발생할 수도 있구요. 명령을 얻어내다가 예외가 발생할 수도 있구요. 언제 예외가 발생할지 모릅니다. 만약 명령을 얻어내다가 예외가 발생하였다면 ResultSet rs 변수는 Null 인 상태 그대로였을 겁니다. Null 인 상태에서 rs.close( ) 를 실행하게 되면 NullPointerException 을 발생시킬 겁니다. 그래서 예외가 발생할 상황들에 대해서 미리 예외처리를 구현해주는 것이 좋습니다. 그래서 rs != null 인 경우에 rs.close( ) 를 수행하도록 코드를 작성합니다. 

같은 방법으로 Statement 객체와 Connection 객체도 닫아주는 코드를 작성하겠습니다. 닫을 때는 생성한 역순으로 닫아주어야 하는 것 잊지 않으셨죠? 이렇게 예외처리를 미리 준비하여 생성한 객체들을 닫아주는 finally 블록을 작성하였습니다. 

그 다음은 Driver 를 로딩해야 합니다. 실제 우리는 mySQL을 사용하기 때문에 MySQL 이 제공하는 드라이버가 메모리에 올라오는 작업을 수행해주어야 합니다. 이 작업을 하기 위해서 Class 객체가 가지고 있는 forName 메서드를 활용하여 Driver 를 로딩시킬 수 있습니다. 

그 다음에는 Connection 객체를 얻어와야 겠죠. DriverManager 라는 클래스가 가지고 있는 getConnection 이라는 메서드를 이용하면 됩니다. 이때 내가 접속할 DB의 URL, User, Password 의 정보를 매개변수로 지정해줘야 합니다. 이렇게 Connection 객체를 얻어오는 것은 많이 실행되는 코드입니다. 따라서 dburl, dbuser, dbpassword 를 변수로 지정한 다음 DriverManager 의 getConnection 메서드를 사용하도록 하겠습니다. 

여기까지 진행했다면 우리는 접속을 할 수 있는 Connection 객체를 얻어왔습니다. Connection 객체를 통해서 Statement 객체를 얻어올 수 있습니다. Statement 객체를 얻어오기 위해서는 쿼리문을 작성해주어야 합니다. 'Select role_id, description From role Where role_id = ?' 라는 쿼리를 String sql 이라는 변수에 담았습니다. 이 sql 을 Connection 객체의 prepareStatement 함수의 인자로 넣어서 PreparedStatement 객체를 얻었습니다.


여기서 ? 물음표가 궁금한데요. 우리는 getRole 이라는 함수가 실행될 때 매개변수로 들어오는 roleId 라는 값에 해당하는 데이터를 찾아와야 합니다. 즉 매번 사용자가 입력하는 값에 따라 수행 결과가 달라지는데요. 이런 부분들을 수행할 때 ? 물음표를 사용하는 것이 PreparedStatement 의 쿼리형식입니다. 이렇게 ? 물음표를 활용하여 작성을 하면 쿼리 자체가 변경되지 않고 ? 물음표가 바인딩되는 부분만 바뀌기 때문에 쿼리가 수행되는 효율이 훨씬 좋아집니다. 반드시 이어서 해주어야 하는 부분이 바로 ? 물음표의 값을 지정해주는 부분인데요. 그 부분은 preparedStatement 가 가지고 있는 set 메서드를 이용하면 됩니다. 현재 우리가 매개변수로 받는 role_Id 가 Integer 이기 때문에 setInt( ) 라는 메서드를 사용하면 됩니다. preparedStatement 객체의 setInt( ) 메서드는 2개의 매개변수를 받는데요. 첫 번째 매개변수인 parameterIndex 에는 ? 물음표의 순서를 의미합니다. 현재 우리 쿼리에 물음표는 하나밖에 없으니까 1 을 입력해주면 됩니다. ? 물음표 대신 들어갈 값을 입력하는 것이 2번째 매개변수인 x 입니다. getRole( ) 메서드의 인자인 roleId 를 넣어주면 됩니다. 

여기까지 작성을 하였으면 '실행을 해주세요' 라는 코드를 작성해주어야 합니다. '실행을 해주세요'라는 코드는 preparedStatement 객체의 excuteQuery( )라는 메서드입니다. 이렇게 Statement 를 실행한 결과 값을 ResultSet 객체에 담아주면 되는 겁니다. 이를 코드로 rs = ps.executeQuery( ) 로 작성하였습니다. 

그 다음에는 결과 값에 담긴 것을 꺼내서 확인하면 됩니다. 우선, rs 에 담긴 값이 없을 수도 있습니다. roleId 에 해당하는 데이터가 데이터베이스에 없을 수 있죠. 그럴 때는 실행하면 예외가 발생하니까 예외 처리를 해주어야 합니다. ResultSet 객체는 next( ) 메서드가 있습니다. next( ) 메서드는 boolean 리턴을 해주는데요. ResultSet 에 담긴 결과 값이 있다면 첫 번째 레코드로 커서를 이동시킨다음 true 를 리턴시켜줍니다. 만약 다음 담겨 있는 값이 없다면 false 를 리턴시켜 줍니다.

만약 결과 값이 있다면 값을 꺼내와야 겠죠. 값을 꺼내오는 것은 ResultSet 객체의 get 메서드를 이용하면 됩니다. ResultSet 객체의 get 메서드를 사용할 때는 우리가 작성한 sql 문에서 나열함 컬럼의 순서가 중요합니다. 예를 들어서 description 이 role_id 보다 먼저 작성을 하였다면 첫 번째 컬럼이 됩니다. 즉 ResultSet 객체의 get( ) 메서드는 다음과 같이 작성해야 합니다. rs.getString(1) 인 것이죠. 첫 번쨰 컬럼은 String 인 것을 반영한 메서드입니다. 그런데 get( ) 메서드의 인자로는 컬럼 순서 말고 컬럼의 이름으로 작성하여도 됩니다. rs.getInt("role_id") 이런 식으로 말이죠.

rs.get( ) 메서드는 컬럼에 해당하는 값을 가져오는 역할을 합니다. 그런데 수행만 하고 값을 변수에 담지 않으면 안되겠죠. 꺼낸 값을 변수에 대입해줍니다. 

이렇게 데이터베이스에서 role_id 를 기준으로 검색한 값 하나를 꺼내서 변수에 담았습니다. 이제 꺼낸 값을 저장할 수 있는 객체인 Role 객체에 담아주면 됩니다. 즉 Role 객체에 꺼낸 값인 role_id 와 description 을 매개변수로 갖는 생성자를 실행시켜 인스턴스를 생성하는 것을 의미합니다. 

 

Role, RoleDao 테스트 해보기
이렇게 데이터베이스에서 값을 꺼내와서 객체에 저장하는 클래스들을 구현했습니다. 실제로 테스트를 진행해보겠습니다. 

RoleDao 객체를 하나 생성해줍니다. 그 다음에는 RoleDao 가 가지고 있는 getRole 메서드를 실행하면 되는데, 내가 찾고자 하는 role_id 를 인자로 넣어주면 됩니다. 그렇게 꺼낸 값을 변수에 담아주고 해당 결과를 우리가 확인해보면 됩니다. 

실행을 시켜 보니까 다음과 같이 출력 결과를 확인할 수 있습니다. role_id 100 번에 해당하는 자료의 description 에 Developer 가 들어있는 것을 확인할 수 있습니다.

정말 데이터가 잘 가져왔는지 DB 에 직접 확인해보겠습니다. 같은 값을 보여주고 있는 것을 확인할 수 있습니다. 

 

수업을 마치며
JDBC 는 이렇게 진행을 하시면 됩니다. 이번에는 한 건 Select 해오는 예제를 수행해 보았는데요. 다음에는 입력하는 예제를 수행해보도록 하겠습니다. 

 

 

 

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