내 블로그 목록

2018년 7월 16일 월요일

[JSP] 일간 뷰어 인터뷰_JDBC편 2

Q. 저번 시간에는 JDBC에 대하여 배워보았다. 기억이 잘 나지 않는다. 리마인드 시켜달라.


JDBC는 DB에 있는 데이터를 JAVA를 거쳐 JSP까지 가져오기 위한 프로그래밍이다. JDBC을 사용하는
일반적인 순서는 다음과 같다.


연결 - 명령어 전송 - 결과 전송 - 연결 종료.


각 과정에서의 키워드를 뽑아보겠다.


연결 - (1) 드라이버로드 (2)Connection 객체
명령어 전송 - (1)Statement (2)Preparement
결과 전송 - (1)ResultSet (2) Int
연결종료 - Close 메서드   


JDBC의 주요 강점은 데이터베이스 종류에 영향을 받지 않는다는 것이다. 어떤 종류의 데이터베이스던지
공통의 API를 사용한다.


그러나 여기서 주의해야 할 점은 jar 형태로 제공되는 JDBC 드라이버는 각 DBMS에 알맞은 클라이언트를
사용해야 한다는 것이다. 코드를 보면 Class.forName(“ “) 안에 어떠한 라이브러리를 사용할 것인가 선언(로딩)하는
부분이 있지 않은가. 이때, MySQL, 오라클, MS SQL 등 어떤 DBMS를 사용할 건 가에 따라 이 부분을 달리해야 한다.



Q. 구체적으로 코드를 사용하여 설명해 줄 수 있겠는가?


알겠다. 여전히 싸갈쓰가 바갈쓰다.


// 1. JDBC 드라이버 로딩
Class.forName("com.mysql.jdbc.Driver"*); // mysql
// oracle.jdbc.driver.OracleDriver
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 2. 데이터베이스 커넥션 생성
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/chap12*", "user", "pass");
// 3. Statement 생성
stmt = conn.createStatement();
// 4. 쿼리 실행
rs = stmt.executeQuery("select * from MEMBER order by MEMBERID")*;


// 5. 쿼리 실행 결과 출력
while(rs.next())* {
String name = rs.getString(1);
}
} catch(SQLException ex) {
ex.printStackTrace();
} finally* {
         // 6. 사용한 Statement 종료
if (rs != null) try { rs.close(); } catch(SQLException ex) {}
  if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
         // 7. 커넥션 종료
if (conn != null) try { conn.close(); } catch(SQLException ex) {}
}


* 클라이언트의 종류에 따른 JDBC 드라이버는 다음과 같다.
 • MySQL - com.mysql.jdbc.Driver
 • 오라클 - oracle.jdbc.driver.OracleDriver
 • MS SQL 서버 - com.microsoft.sqlserver.jdbc.SQLServerDriver


*JDBC URL 구성은 다음과 같다.
– MySQL : jdbc:mysql://HOST[:PORT]/DBNAME[?param=value&par am1=value2&...]
– Oracle: jdbc:oracle:thin:@HOST:PORT:SID
– MS SQL : jdbc:sqlserver://HOST[:PORT];databaseName=DB


*때에 따라서는
String jdbcDriver = "jdbc:mysql://localhost:3306*/chap11?" + "useUnicode=true&characterEncoding=utf-8"
이런 식으로 고대 문자들의 모음 처럼 있는 경우도 있다. 첫 번째 부분은 본인이 저번 시간에 주석처리로
설명했다. 두 번째 부분은 버전(Version)을 명시하는 것이다.


*Oracle 1521, MySQL 3306, FTP 21, HTTP 80, Tomcate 8080 이 포트번호들은 외워두는 것이 좋다.
포트 번호 변경 사용 가능하다.


*finally는 무조건 실행해야 하는 부분을 감싸 주는 것이다. Must do it part.


*너무 중요해서, 다시한번 리마인드 시켜준다. 💀💀💀
Statement가 제공하는 메서드로 쿼리 실행
ResultSet executeQuery(String query) : SELECT 쿼리를 실행
int executeUpdate(String query) : INSERT, UPDATE, DELETE 쿼리 를 실행


Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
int insertedCount = stmt.executeUpdate("insert …..");
rs = stmt.executeQuery("select * from ….");
} catch(SQLException ex) {
… } finally {
if (rs != null) try { rs.close(); } catch(SQLException ex) {}
if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
}


* While(rs.next()) 원리를 설명하기 위해, 그림을 불펌했다.
화살표를 잘 보아라.
While(rs.next())는 ‘나 지금 행 읽는 거 끝나고 다음 행 읽는 거 반복 할 건데, 다음에 읽을 꺼 있어?’라고
확인하고 반복하는 부분이다.


혹시나 해서 말하는 것인데, 아시다 시피 행이 하나 일 경우에는
while(rs.next()) 대신에 if(rs.next()) 를 통해서 처리한다.





Q. 궁금한 부분이 생겼다. JDBC는 주로 java 파일에서 처리했다. 그러나 내가 DB에서 받은 값을 웹
상에서 출력하고 싶으면 어떻게 해야 하는가?


JSP 파일을 이용하면 된다. 커넥션을 받고 값을 받고 이것을 출력하기 까지를 <%%>로 처리하면 된다.


다만, 주의해야 할 부분은 읽어오는 문법은 다음과 같다.


// 4. 쿼리 실행
rs = stmt.executeQuery(query);


// 5. 쿼리 실행 결과 출력
while(rs.next()) { %>


<%= rs.getString("ENAME") %>
<%= rs.getString("EMPNO") %>
<%= rs.getString("JOB") %>


<% }
} catch(SQLException ex) {
out.println(ex.getMessage());
ex.printStackTrace();
}





Q. 오늘은 어떤 새로운 내용을 신나고 재미나게 배울 것인가?


오늘의 새로운 내용은 앞서 말했던 JDBC 내용과 연결된다. 이번에는 JDBC 드라이버를 선언하는 또
다른 방법을 알아 보도록 하겠다.


JDBC에서 앞 부분에 드라이버를 선언해 주지 않는가. 앞서 말했듯,  DBMS의 종류에 따라 선언 내용이
달라지며, 이 부분이 라이브러리에 서 파일을 불러와 DB 연결/사용하겠다고 알리는 부분이다.  


그런데, 여기서 참고해야 할 것은, Web.xml 파일에 JDBC 드라이버를 먼저 선언해 두고, 우리가
getInitParameter(“”) 메서드로 불러올 수 있다는 것이다.


이 방법을 이용할 때 염두해 두어야 하는 점은 web.xml에 추가한 후  서버를 종료했다가 재시작 해야한다.


예시를 보여주도록 하겠다.




[src/Jdbc/Loader.java ]
package Jdbc;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import java.util.StringTokenizer;


public class Loader extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
try {
String drivers = config.getInitParameter("jdbcdriver");
StringTokenizer st = new StringTokenizer(drivers, ",");
while (st.hasMoreTokens())* {
String jdbcDriver = st.nextToken();
Class.forName(jdbcDriver);
}
} catch(Exception ex) {
throw new ServletException(ex);
}
}
}




[web.xml ]
<servlet>
<servlet-name>JDBCDriverLoader</servlet-name>
<servlet-class>Jdbc.Loader</servlet-class>
<init-param>
<param-name>jdbcdriver</param-name>
<param-value>oracle.jdbc.driver.OracleDriver</param-value>*
</init-param>
<load-on-startup>1</load-on-startup>*
</servlet>


*여기서 가장 핵심은 config.getInitParameter(“”) 메서드 이다.


*StringTokenizer를 이용해서 “,”를 기준으로 jdbcdriver를 잘라 사용한다.  
이는 <param-value>에 여러 개의 드라이버가 있을 경우를 대비하는 것이다.


예를 들어,
<param-value>oracle.jdbc.driver.OracleDriver,  MysqlDriver </param-value>
이렇게 있다면, (1) oracle.jdbc.driver.OracleDriver (2) MysqlDriver 이렇게 잘라서, (1)을 먼저 실행하고,
그 후에 (2)를 실행한다.


StringTokenizer 부분은 생략 가능하다. 생략한 코드는 다음과 같다.


import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
public class Loader extends HttpServlet {
  
public void init(ServletConfig config) throws ServletException {
String drivers = config.getInitParameter("jdbcdriver");
try {
Class.forName(drivers);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


*<load-on-startup>1</load-on-startup>은 실행 횟수이다.





Q. 별로 재미가 없다. 새로운 또 다른 것을 가르쳐 달라.
그럼 이번에는 커밋(Commit)과 롤백(Rollback)에 대해 알아보도록 하겠다.


커밋을 해야하는 시간은, 하나의 트랜잭션이 끝나고이다. 트랜잭션*은 저번에 배웠다. 이 문답
끝 부분에 다시 요약 추가 하겠다 .


커밋을 하는 방법은 Connection에 있는 setAutoCommit(false) 메서드를 사용하는 것이다.
커밋을 하기 위하여  setAutoCommit(false)를 시발점으로 선언하고, conn.commit() 메서드가
실행 결과를 커밋한다. 예시 코드는 다음과 같다.


<Connection.setAutoCommit(false)>


try {
conn = DriverManager.getConnection(...);
// 트랜잭션 시작
conn.setAutoCommit(false);
... // 쿼리 실행
... // 쿼리 실행
// 트랜잭션 커밋
conn.commit();
} catch(SQLException ex) {
if (conn != null) {
// 트랜잭션 롤백
conn.rollback();
}
} finally {
if (conn != null) {
try {
conn.close();
} catch(SQLException ex) {}
}
}


만약 내가 적어놓은 코드를 정상 실행 했다면,  conn.commit()메서드가 정상적으로 커밋한다.


그러나, 코드들이 정상 실행 되지 못하고 예외가 발생했다면, 예외 안에 있는 conn.rollback();이
입력된 실행문들과 그 결과값을 취소해버리고 setAutoCommit(false); 때의 데이터 값으로 다시
돌아간다. Reset의 개념과 같다.




*본인 스스로 트랜잭션의 개념을 리마인드 하기 위해, 드라이브에서 가져왔다.


트랜잭션 = 여러 개의 SQL 명령문들을 하나의 논리적인 작업 단위로 처리하는 것.
                  All-OR-Nothing 방식*으로 처리
                  트랜젝션은 데이터의 일관성을 유지하기 위해 고안.


*한꺼번에 모든 sql문을 처리하거나 모두 하지 않거나. 명령어 처리 도중 하나의 명령어라도
잘못 되면 전체 실행 취소해버림. 모두 실행 후에는 정상 종료.


ex) 은행 atm의 트랜젝션
현금인출 신청
  현금카드 삽입 후 본인 인증
인출금액 선택
atm에서 현금 습득
계좌에 인출 금액 만큼 차감


  만약 중간 과정에서 오류 발생이 되면, 전체 취소

댓글 3개: