학습(구)/JSP

DB연동-JDBC

잉아당 2020. 9. 18. 00:29
728x90

웹 서버 애플리케이션은 프로그램의 영속성(DB에 기록하는 성질) 제어를 위해 관련 자료를 DB서버에 저장하여 사용합니다.

이때는 DB에 직접 접근하여 사용하는것이 아니라 DB서버와 관계엾이 DB와 연동이 가능하도록 JDBC API를 사용합니다.

JDBC를 사용하면 프로그램 변동없이 드라이버 변동으로 DB서버 변경이 가능합니다.

 

JDBC API

JDBC API를 사용하기 위해서는 DBMS에 알맞은 JDBC 드라이버가 필요합니다.

JDBC 드라이버 파일인 .jar를 WEB-INF/lib에 복사하여 사용합니다.

드라이버 클래스는 사용할때 다른 클래스와 달리 반드시 Class.forName()을 사용하여 런타임 로딩(동적로딩)을 해야합니다.

이는 드라이버 클래스가 로딩될 때 DriverManager 객체의 자동 생성 및 등록 등 여러가지 전처리가 static 블록에서 이루어지기 때문입니다.

static 블록은 클래스가 로딩될 때 클래스 변수가 준비된 후 자동으로 실행되는 블록입니다.

이러한 동적 로딩은 DB서버 접근때 마다 수행하는 것은 비효율적이므로 서블릿의 init 메서드를 사용하여 애플리케이션이 시작될 때 드라이버 클래스를 한번만 로딩하는 것이 좋습니다.

import javax.servlet.http.HttpServlet;
import javax.servlet.ServletConfig; 
import javax.servlet.ServletException;
public class MySQLJDBCDriverLoader extends HttpServlet {
// 객체 생성시 맨 처음 호출되는 초기화 메서드
public void init(ServletConfig config) throws ServletException {
try { 
 Class.forName("com.mysql.jdbc.Driver");
} catch(Exception ex) {
throw new ServletException(ex);
  } 
 }
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version ="3.1">
<servlet> 
<servlet-name>mysqlDriverLoader</servlet-name>
<servlet-class>chap08.JDBCDriver.MySQLJDBCDriverLoader</servlet-class> 
<!-- WAS 구동시 객체 생성 --> 
<load-on-startup>1</load-on-startup>
</servlet> 
</web-app>

=> 드라이버 클래스를 런타임 로딩 하는 클래스를 생성후 web.xml에 등록하여 사용합니다.

 

<%@ page contentType = "text/html; charset=utf-8" %>
<%@ page import = "java.sql.DriverManager" %> 
<%@ page import = "java.sql.Connection" %> 
<%@ page import = "java.sql.Statement" %> 
<%@ page import = "java.sql.SQLException" %> 
<%
request.setCharacterEncoding("utf-8"); 
String id = request.getParameter("id");
String club = request.getParameter("club");
int updateCount = 0;
// 객체 참조 변수 준비 
Connection conn = null; 
Statement stmt = null; 
try {
// jdbcURL : 데이터베이스 지정
String jdbcURL = "jdbc:mysql://localhost:3306/chap08?" 
    + "useUnicode=true&characterEncoding=utf8";
// user, password 지정
String user = "root";
String pwd = "1111";
// 쿼리 준비
String query = "update MEMBER set CLUB = '"+club+"' "+
"where ID = '"+id+"'"; // DriverManager 클래스를 사용하여 connection 객체 구함
conn = DriverManager.getConnection(jdbcURL, user, pwd);
// Statement 생성
stmt = conn.createStatement();
// Statement 객체로 쿼리 실행
updateCount = stmt.executeUpdate(query);
} catch(SQLException ex) {
 out.println(ex.getMessage());
ex.printStackTrace(); 
} finally {
if (stmt != null) try { stmt.close(); } catch(SQLException ex) {} 
if (conn != null) try { conn.close(); } catch(SQLException ex) {}
}
%>
// 사용했던 자원 반납
<html>
<head><title>전공동아리 변경</title></head> 
<body>
<% if (updateCount > 0) { %>
<%= id %>의 전공동아리를 <%= club %>로 변경 
<% }else{%>
<%= id %> 아이디가 존재하지 않음
<% }%>
</body> 
</html>

동적 로딩에 의해 생성되는 DriverManager 클래스를 사용하여 DB를 식별하는 JDBC URL, ID, PWD로 DB에 접속하는 Connection을 생성합니다. 그런다음 Connection객체로 부터 Statement객체를 생성한 후 query를 이용하여 Statement객체의 의한 DB 동작을 수행합니다.

 

이때 select의 경우 executeQuery(쿼리문)메서드를 수행하고 update,delete,insert의 경우 executeUpdate(쿼리문)메서드를 수행합니다.

update,delete,insert의 경우 수정된 레코드 수가 반환됩니다.

select의 경우에는 ResultSet을 리턴합니다.

ResultSet은 작은 레코드 테이블입니다. 테이블의 행을 가리키는 커서가 존재하고 next 메서드를 제공하여 커서가 다음 행을 가리키게 할 수 있습니다.

<%
while(rs.next()) { 
%>
<tr>
 <td><%= rs.getString("ID") %></td>
 <td><%= rs.getString("PWD") %></td>
 <td><%= rs.getString("NAME") %></td> 
 <td><%= rs.getString("GRADE") %></td> 
 <td><%= rs.getString("CLASS") %></td>
 <td><%= rs.getString("CLUB") %></td>
</tr>
<% } %>

<%
if (rs != null) try { rs.close(); } catch(SQLException ex) {}
%>

while을 사용하여 반복하며 next메서드를 사용해 다음행을 가리키며 행의 정보를 얻습니다. 

 

DB관련 수행은 익셉션을 발생시키므로 try - catch 블록으로 처리해야하며 DB서버 사용이 종료되면 사용했던 자원인 Connection, Statement,ResultSet 등을 반납해야하는데 익셉션이 발생하므로 try - catch 블록으로 처리해야합니다.

자원 생성 과정에서 익셉션 발생에 의해 그 자원이 생성되지 않았을 수도 있다는 점을 고려해야 하고 close 메서드 수행이 다시 익셉션을 발생 시킬 수 있기 때문에 이를 다시 try - catch블럭으로 처리해야 하는 이유입니다.

 

객체지향에서는 여러 개의 데이터를 하나의 단위로 다룰떄에는 객체로 관리합니다. 그러므로 여러개의 칼럼으로 이루어진 한 행을 하나의 객체로 다루고 ResultSet은 객체 리스트로 처리합니다.

 

쿼리에서 값을 표현할 때는 작은 따옴표로 감싸서 표현합니다.

st.executeQuery(“UPDATE MEMBER SET NAME = ‘” + name + “’ WHERE MEMBERID = ‘” + id + “’”) ;

PreparedStatement 객체는 Statement객체와 동일한 기능을 수행하는 객체인데 미리 쿼리의 틀을 준비하고 값을 나중에 지정할 때 사용합니다.

PreparedStatment pst = conn.prepareStatement( “INSERT INTO MEMBER VALUES (?, ?, ?, ?, ?, ?”) ;
pst.setString(1, “LeeTY”) ; // 1번째 인덱스 파라미터 값 지정 
pst.setString(2, “Lee0301”) ; // 2번째 인덱스 파라미터 값 지정 
pst.setString(3, “Lee Tae Yang”) ; // 3번째 인덱스 파라미터 값 지정 
pst.setString(4, “3”) ; // 4번째 인덱스 파라미터 값 지정 
pst.setString(5, “A”) ; // 5번째 인덱스 파라미터 값 지정 
pst.setString(6, “Smart Factory”) ; // 6번째 인덱스 파라미터 값 지정

JDBC API를 이용해 2개 이상의 쿼리를 트랜잭션 처리하려면 Connection객체의 setAutoCommit 메서드에 false를 전달하여 자동 commit을 중지하면 트랜잭션이 시작됩니다.

try 블럭에서 commit을 수행하며 오류가 발생할 경우 catch블럭에서 rollback을 수행합니다.

 

'학습(구) > JSP' 카테고리의 다른 글

디자인 패턴 - 생성 패턴  (0) 2020.11.16
JDBC - 커넥션 풀  (0) 2020.09.18
커스텀 태그  (0) 2020.09.17
JSTL - fmt태그  (0) 2020.09.17
JSTL - core태그  (0) 2020.09.17