본문 바로가기

Java/JSP

07.10 connection pool (7.7 실습문제 풀이)

커넥션 풀의 장점 : 서버안정화, 커넥션을 할 때 시간단축

 


 

src/main/java/util/JDBCUtil.java

 

package util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * database 연결 작업 및 자원해제를 도와줄 Util class
 */
public class JDBCUtil {

/**
 * database 연결에 필요한 필수 정보
 */
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/digital_jsp";
private static final String USER = "digital";
private static final String PASS = "12345";

public static Connection getConnection() {
Connection conn = null;
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL,USER,PASS);
} catch (ClassNotFoundException e) {
System.out.println("DriverClass를 찾을 수 없음");
} catch (SQLException e) {
System.out.println("연결 요청 정보 오류 : "+e.getMessage());
}
return conn;
}
// ...하면 갯수에 상관없이 배열로 넘겨받음
public static void close(AutoCloseable... closer) {
for(AutoCloseable c : closer) {
if(c != null) {
try {
c.close();
} catch (Exception e) {}
}// not null
}// end for
}// end close
}

 


커넥션 풀 구현

<?xml version="1.0" encoding="UTF-8"?>

<!-- wabapp/META-INF/context.xml -->

<Context>

<!-- 모든 프로젝트에서 사용하고 싶으면 tomcat에 넣어주면 된다. -->

<!-- Resource: 자바 클래스 -->

<!-- auth : 어디서 생성해서 관리할건가(우리는 서버 컨테이너에서 관리할거임)

DataSource : 커넥션 풀 표준인터페이스

factory : 해당 클래스 -->

<Resource name="java/MySQLDB"

auth="container"

type="javax.sql.DataSource"

factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"

driverClassName="com.mysql.cj.jdbc.Driver"

url="jdbc:mysql://localhost:3306/digital_jsp"

username="digital"

password="12345"

maxActive="200"

maxIdle="100"

minIdle="10"

maxWait="600000" />

<!--

maxActive : 동시에 사용할 수 있는 최대 커넥션 개수(기본값 : 8)

maxIdle : 커넥션 풀에 반납할 때 최대로 유지될 수 있는 커넥션 개수(기본값:8)

minIdle : 최소한으로 유지할 커넥션 개수(기본값 : 0)

maxWait :(millis) 할당받을 Connection 객체가 없을 때 스레드를 블럭시킬 시간

-->

</Context>

src/main/java/util/DBCPUtil.java

 

package util;

import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
 * database Connection Pool에서
 * Connection 정보를 반환
 */

public class DBCPUtil extends JDBCUtil {

public static Connection getConnection() {
Connection conn = null;
try {
// javax.naming.Context;
// JNDI(Java Naming and Directory Interface)
// 디렉토리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바 API
// context에 등록된 name 정보로 resource를 저장하고 있는 객체
Context context = new InitialContext();
/* java:comp/env/ : 예약어 */
DataSource ds = (DataSource)context.lookup("java:comp/env/java/MySQLDB");
conn = ds.getConnection();
} catch (NamingException e) {
// 일치하는 name 없을 수 도 있으니까 예외처리
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}

}

 


사용 예

 

<%

Connection conn = DBCPUtil.getConnection();

PreparedStatement pstmt = null;

ResultSet rs = null;

 


<%

String sql = "SELECT id, name, addr FROM test_member WHERE num = ? ";

String num = request.getParameter("num");

Connection conn = DBCPUtil.getConnection();

PreparedStatement pstmt = null;

ResultSet rs = null;

MemberVO vo = null;

 

try{

pstmt = conn.prepareStatement(sql);

pstmt.setInt(1,Integer.parseInt(num));

rs = pstmt.executeQuery();

 

if(rs.next()){

// 일치하는 회원정보 찾음

vo = new MemberVO();

// 속성을 지정해서 꺼내올 때, 내가 지정한 순서대로 정수로 꺼내올 수 있다.

vo.setId(rs.getString(1));

vo.setName(rs.getString(2));

vo.setAddr(rs.getString(3));

vo.setNum(Integer.parseInt(num));

}else{

throw new NullPointerException("회원정보 없음");

}

 

}catch(Exception e){

out.println("<script>");

out.println("alert('입력하신 정보의 회원이 존재하지 않습니다.');");

out.println("history.go(-1);");

out.println("</script>");

 

}finally{

DBCPUtil.close(rs,pstmt,conn);

}


a태그 접두어로 javascript: 하면 이동하지 않고 스크립트 실행

 

<tr>

<th colspan="2">

<!-- a태그 접두어로 javascript: 하면 이동하지 않고 스크립트 실행-->

<a href="">수정</a> | <a href="javascript:memberDelete();">삭제</a>

</th>

</tr>

</table>

<script>

function memberDelete(){

if('<%=vo.getId()%>' == 'admin'){

alert('관리자 계정은 삭제할 수 없습니다.');

return;

}

if(confirm('<%=vo.getNum()%>'+"번 회원 정보를 정말로 삭제하시겠습니까?")){

// 확인버튼 눌리면 실행

location.href='memberDelete.jsp?num='+'<%=vo.getNum()%>';

}

}

</script>

회원번호 전달 2번째 방법

<!-- a태그 접두어로 javascript: 하면 이동하지 않고 스크립트 실행-->

<a href="javascript:memberUpdate('<%=vo.getNum()%>');">수정</a>

</th>

</tr>

</table>

<script>

// 회원정보 수정 페이지 요청

function memberUpdate(num){

location.href='index.jsp?page=memberUpdateForm&num='+num;

}

 

쿼리문 이어서 작성하는 경우 공백 확인 잘하기!!

 

Connection conn = DBCPUtil.getConnection();

PreparedStatement pstmt = null;

// 이어서 작성하는 경우 좌우 공백 확인 잘 하기!!

String sql = "UPDATE test_member SET";

sql += " id = ?, ";

sql += " pass = ?, ";

sql += " name = ?, ";

sql += " addr = ?, ";

sql += " phone = ?, ";

sql += " gender = ?, ";

sql += " age = ? ";

sql += " WHERE num = ? ";

 

pstmt = conn.prepareStatement(sql);

pstmt.setString(1,m.getId());

pstmt.setString(2,m.getPass());

pstmt.setString(3,m.getName());

pstmt.setString(4,m.getAddr());

pstmt.setString(5,m.getPhone());

pstmt.setString(6,m.getGender());

pstmt.setInt(7,m.getAge());

pstmt.setInt(8,m.getNum());

 

pstmt.executeUpdate();

DBCPUtil.close(pstmt,conn);

response.sendRedirect("index.jsp?page=memberList");

관리자만 수행할 수 있는 페이지들은 권한 확인 해주고 있음..

 

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!-- checkAdmin.jsp -->

<jsp:useBean id="loginMember" class="vo.MemberVO" scope="session"/>

<%

if(loginMember.getId() == null || !loginMember.getId().equals("admin")){

out.println("<script>");

out.println("alert('올바른 접근이 아닙니다.');");

out.println("history.back()");

out.println("</script>");

return;

}

%>

관리자권한이 필요한 페이지에 

<%@ include file="checkAdmin.jsp" %>

추가해줌