본문 바로가기

Programming/국비학원

220923 - 서블릿 - DB 연결, 커넥션풀

서블릿 - DB 연결

1. servletdb 프로젝트 생성
프로젝트 우클릭 - build path - classpath 에 add external jars -  servlet-api.jar 추가

2. sqldeveloper 테이블 생성 (member_list)
id,pwd,name,email,joindate

3. 프로젝트 폴더에 오라클 드라이버 넣기 
ojdbc8jar webapp/web-inf/lib에 붙여넣기

 

 

 

  • 회원가입 (post 방식)
  • MemberServlet.java
package servletdb.ex01;

import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/member")
public class MemberServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		MemberDAO dao = new MemberDAO(); //SQL문으로 조회할 MemberDAO 객체
		List<MemberVO> list = dao.listMembers(); //회원리스트 불러오기
		out.print("<html><body>");
		out.print("<table border=1>");
		out.print("<tr align='center' bgcolor='azure'>");
		out.print("<th>아이디</th><th>비밀번호</th><th>이름</th><th>이메일</th><th>가입일자</th></tr>");
		for (int i=0;i<list.size();i++) {
			out.print("<tr><td>"+list.get(i).getId()+"</td><td>"+list.get(i).getPwd()+"</td><td>"
					+list.get(i).getName()+"</td><td>"+list.get(i).getEmail()
					+"</td><td>"+list.get(i).getJoindate()+"</td></tr>");
		}
		out.print("</table>");
		out.print("</body></html>");
	}
}

 

 

 

※ sqldeveloper 사용자계정 우클릭 - 속성 - 호스트 이름 확인

  • servletdb.ex01/MemberDAO.java

=> Data Access Object : 데이터베이스 연동, 기능(회원리스트 리턴) 수행할 클래스 

 

(서블릿-회원정보 데이터베이스 연결, 쿼리 실행, 각 컬럼값 변수에 담은 후 MemberVO 회원정보 객체에 값 세팅, 회원정보목록에 MemberVO 객체 하나씩 담기)

 

 

package servletdb.ex01;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class MemberDAO {

	private static final String driver = "oracle.jdbc.driver.OracleDriver";
	private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
	private static final String user = "데이터베이스 아이디";
	private static final String pwd = "비번";
	private Connection con; //db 연동 객체
	private Statement stmt; //쿼리문 실행 명령 (=sqldeveloper 실행 버튼)
	
	//회원정보 목록 처리
	public List<MemberVO> listMembers(){
		List<MemberVO> list = new ArrayList<MemberVO>();
		try {
			connDB(); 
			String query = "select * from member_list"; //실행할 쿼리문
			ResultSet rs = stmt.executeQuery(query);  //쿼리문 파라미터를 실행, 결과를 ResultSet 변수에 담음
			while(rs.next()) { //rs => 커서 역할 (검색 결과 집합)
				String id = rs.getString("id"); //컬럼값 하나 가져옴 (1번째, 2번째, ..) //파라미터로 0도 가능(0번째 컬럼)
				String pwd = rs.getString("pwd");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date joinDate = rs.getDate("joindate");
				//데이터타입 숫자일 시 getInt 또는 getDouble
				
				MemberVO vo = new MemberVO(); //위 객체들 담음
				vo.setId(id);
				vo.setPwd(pwd);
				vo.setName(name);
				vo.setEmail(email);
				vo.setJoindate(joinDate);
				
				list.add(vo);
			}
			rs.close();
			stmt.close();
			con.close();
		} catch (Exception e){
			System.out.println("자료 처리 중 에러 발생");
		}
		return list;
	}
	
	//데이터베이스 연결,  상태 확인
	private void connDB() {
		try {
			Class.forName(driver);
			System.out.println("오라클 드라이버 로딩 성공");
			con = DriverManager.getConnection(url,user,pwd);
			System.out.println("Connection 생성 성공");
			stmt = con.createStatement();
			System.out.println("Statement 생성 성공");
		} catch(Exception e) {
			System.out.println("DB 연결 실패"); //web-inf/lib/드라이버.jar 파일 설치 오류
		}
	}
	
}

 

 

 

  • MemberVO.java

=> ValueObject : 컬럼들의 정보 저장할 클래스 (각 회원의 정보)

 

 

package servletdb.ex01;

import java.sql.Date;

public class MemberVO {
	
	private String id; //캡슐화 => 정보 은닉
	private String pwd;
	private String name;
	private String email;
	private Date joindate;
	
	public MemberVO() {
		System.out.println("MemberVO 생성자 호출");
	}
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Date getJoindate() {
		return joindate;
	}
	public void setJoindate(Date joindate) {
		this.joindate = joindate;
	}
	
}

 

 

 

 

https://surhommejk.tistory.com/285

커넥션 풀 (Conection Pool) 통해 데이터베이스 연동

JDBC 드라이버를 통해 자바-데이터베이스 연결하는 작업을 모든 요청마다 매번 새로 처리
=> 네트워크 연결과 해제를 계속 반복하면서 성능 저하
=> 커넥션 풀로 해결

 

커넥션 풀 : 웹 애플리케이션 실행과 동시에 연동할 데이터베이스와의 연결을 미리 설정해둠
->필요할 때마다 미리 연결한 상태를 이용해 빠르게 데이터베이스와 연동
=> 미리 데이터베이스와 연결시킨 상태를 유지하는 기술

 

Connection 객체를 미리 생성

=> 요청이 있을 때마다 생성된 Connection을 빌려옴

=> 요청 처리 후 Pool에 반납 (반복)

 

사용법
1. 커넥션풀 기능 관련 jar 파일을 /WEB-INF/lib 폴더에 설치
2. 객체 생성 시 연결할 데이터베이스 정보를 JNDI로 설정
3. DAO 클래스에서 데이터베이스 연동 시 미리 설정한 JNDI로 연결 (HashMap형태)

 

 

 

 

  • 커넥션풀 사용 전
  • MemberVO

 

 

  • MemberServlet
package servletdb.ex02;

import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/member2") ////
public class MemberServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		MemberDAO dao = new MemberDAO(); //SQL문으로 조회할 MemberDAO 객체
		List<MemberVO> list = dao.listMembers();
		out.print("<html><body>");
		out.print("<table border=1>");
		out.print("<tr align='center' bgcolor='azure'>");
		out.print("<th>아이디</th><th>비밀번호</th><th>이름</th><th>이메일</th><th>가입일자</th></tr>");
		for (int i=0;i<list.size();i++) {
			out.print("<tr><td>"+list.get(i).getId()+"</td><td>"+list.get(i).getPwd()+"</td><td>"
					+list.get(i).getName()+"</td><td>"+list.get(i).getEmail()
					+"</td><td>"+list.get(i).getJoindate()+"</td></tr>");
		}
		out.print("</table>");
		out.print("</body></html>");
	}
}

 

 

 

  • MemberDAO
package servletdb.ex02;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class MemberDAO {

	private static final String driver = "oracle.jdbc.driver.OracleDriver";
	private static final String url = "jdbc:oracle:thin:@DESKTOP-HU410J6:1521:XE";
	private static final String user = "userdb";
	private static final String pwd = "1234";
	private Connection con; //db 연동 객체
	//private Statement stmt; //단점 : db 연동할 때마다 sql문 컴파일 -> 속도 느림
	private PreparedStatement pstmt; //sql문 미리 컴파일 후 재사용 //연동, 반복 처리에 유용 //데이터베이스 컬럼 가져올 때 명령어 간결 (?) /////
	
	//회원정보 목록 처리
	public List<MemberVO> listMembers(){
		List<MemberVO> list = new ArrayList<MemberVO>();
		try {
			connDB(); //db 연결 (서블릿에서 요청할 때마다)
			String query = "select * from member_list"; //실행할 쿼리문
			pstmt=con.prepareStatement(query); ////연결하면서 쿼리문 가져와 저장하고 있다가 실행할 때마다 불러옴 (cf. 실행하면서 쿼리문 가져옴)
			ResultSet rs = pstmt.executeQuery();  //미리 설정한 sql문 실행 ////
			while(rs.next()) { //rs => 커서 역할 (검색 결과 집합)
				String id = rs.getString("id"); //컬럼값 하나 가져옴 (1번째, 2번째, ..) //파라미터로 0도 가능(0번째 컬럼)
				String pwd = rs.getString("pwd");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date joinDate = rs.getDate("joindate");
				//데이터타입 숫자일 시 getInt 또는 getDouble
				
				MemberVO vo = new MemberVO(); //위 객체들 담음
				vo.setId(id);
				vo.setPwd(pwd);
				vo.setName(name);
				vo.setEmail(email);
				vo.setJoindate(joinDate);
				
				list.add(vo);
			}
			rs.close();
			pstmt.close(); ////
			con.close();
		} catch (Exception e){
			System.out.println("자료 처리 중 에러 발생");
		}
		return list;
	}
	
	//데이터베이스 연결 상태 확인
	private void connDB() {
		try {
			Class.forName(driver);
			System.out.println("오라클 드라이버 로딩 성공");
			con = DriverManager.getConnection(url,user,pwd);
			System.out.println("Connection 생성 성공");
			//pstmt = con.prepareStatement(driver); ////
			//System.out.println("Statement 생성 성공");
		} catch(Exception e) {
			System.out.println("DB 연결 실패"); //web-inf/lib/드라이버.jar 파일 설치 오류
		}
	}
	
}

 

=> 현재 : 웹 애플리케이션에서 데이터베이스 요청이 있을 때마다 데이터베이스를 연결함

=> 비효율적

=> 서버에 맡기기 (=Connection Pool)

 

 

 

  • 커넥션풀 연결

1. 
커넥션풀 관련 jar => WEB-INF/lib 에 저장


2. 서버가 db 연결 담당
Server - context.xml - 컨텍스트 내부에 태그 추가

    <Resource name="jdbc/oracle" auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" 
    url="jdbc:oracle:thin:@DESKTOP-HU410J6:1521:XE" username="userdb" password="1234" maxActive="50" maxWait="-1"></Resource> 

※ maxActive : 동시에 들어올 수 있는 데이터 수

 

 

 

 

  • 커넥션풀 사용 후
  • MemberServlet

매핑주소 변경 (/member3)

 

 

 

  • MemberDAO
package servletdb.ex03;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

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

public class MemberDAO {

//	private static final String driver = "oracle.jdbc.driver.OracleDriver";
//	private static final String url = "jdbc:oracle:thin:@DESKTOP-HU410J6:1521:XE";
//	private static final String user = "userdb";
//	private static final String pwd = "1234";
	private Connection con; //db 연동 객체
	//private Statement stmt; //단점 : db 연동할 때마다 sql문 컴파일 -> 속도 느림 
	private PreparedStatement pstmt; //sql문 미리 컴파일 후 재사용 //연동, 반복 처리에 유용 //데이터베이스 컬럼 가져올 때 명령어 간결 (?) 
	private DataSource dataFactory; //서버에서 데이터 가져옴 ////
	
	public MemberDAO() { ////
		try {
			Context ctx = new InitialContext(); //서버의 컨텍스트 정보 가져오기 위해 연결
			Context envContext = (Context) ctx.lookup("java:/comp/env"); ////
			dataFactory = (DataSource) envContext.lookup("jdbc/oracle"); //미리 연결된 데이터베이스 가져옴 ////
		} catch(Exception e) {
			System.out.println("DB 연결 실패");
		}
	}
	
	//회원정보 목록
	public List<MemberVO> listMembers(){
		List<MemberVO> list = new ArrayList<MemberVO>();
		try {
//			connDB(); //db 연결 (서블릿에서 요청할 때마다)
			con = dataFactory.getConnection(); //서버는 미리 연결된 상태에서 DataSource 이용해 db 연결 ////
			String query = "select * from member_list"; //실행할 쿼리문
			pstmt=con.prepareStatement(query); ////연결하면서 쿼리문 가져와 저장하고 있다가 실행할 때마다 불러옴 (cf. 실행하면서 쿼리문 가져옴)
			ResultSet rs = pstmt.executeQuery();  //미리 설정한 sql문 실행
			while(rs.next()) { //rs => 커서 역할 (검색 결과 집합)
				String id = rs.getString("id"); //컬럼값 하나 가져옴 (1번째, 2번째, ..) //파라미터로 0도 가능(0번째 컬럼)
				String pwd = rs.getString("pwd");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date joinDate = rs.getDate("joindate");
				//데이터타입 숫자일 시 getInt 또는 getDouble
				
				MemberVO vo = new MemberVO(); //위 객체들 담음
				vo.setId(id);
				vo.setPwd(pwd);
				vo.setName(name);
				vo.setEmail(email);
				vo.setJoindate(joinDate);
				
				list.add(vo);
			}
			rs.close();
			pstmt.close(); ////
			con.close();
		} catch (Exception e){
			System.out.println("자료 처리 중 에러 발생");
		}
		return list;
	}
	
//	//데이터베이스 연결 상태 확인
//	private void connDB() {
//		try {
//			Class.forName(driver);
//			System.out.println("오라클 드라이버 로딩 성공");
//			con = DriverManager.getConnection(url,user,pwd);
//			System.out.println("Connection 생성 성공");
//			//pstmt = con.prepareStatement(driver); 
//			//System.out.println("Statement 생성 성공");
//		} catch(Exception e) {
//			System.out.println("DB 연결 실패"); //web-inf/lib/드라이버.jar 파일 설치 오류
//		}
//	}
	
}

 

 

 

 

  • 회원가입 (insert 작업 추가)
  • webapp/memberForm.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입 창</title>
<script type="text/javascript">
	function fn_sendMember(){
		let frmMember = document.frmMember;
		let id = frmMember.id.value;
		let pwd = frmMember.pwd.value;
		let name = frmMember.name.value;
		let email = frmMember.email.value;
		
		if(id.length==0||id==""){
			alert('아이디를 입력해주세요');
		} else if (pwd.length==0||pwd==""){
			alert('비밀번호를 입력해주세요');
		} else if (name.length==0||name==""){
			alert('이름을 입력해주세요');
		} else if (email.length==0||email==""){
			alert('이메일을 입력해주세요');
		} else {
			frmMember.method="post";
			frmMember.action="member4";
			frmMember.submit(); //서블릿을 전송
		}
	}
</script>
</head>
<body>
	<form name=frmMember>
		<h2>회원가입 창</h2>
		<table>
			<tr>
				<td>아이디</td>
				<td><input type="text" name="id"></td>
			</tr>
			<tr>
				<td>비밀번호</td>
				<td><input type="password" name="pwd"></td>
			</tr>
			<tr>
				<td>이름</td>
				<td><input type="text" name="name"></td>
			</tr>
			<tr>
				<td>이메일</td>
				<td><input type="text" name="email"></td>
			</tr>
		</table>
		<input type="button" value="가입하기" onclick="fn_sendMember()">
		<input type="reset" value="다시 입력">
		<input type="hidden" name="command" value="addMember"> <!-- ★어떤 목적(탈퇴면 value="delMember")으로 서버에 접근하는지 확인 -->
	</form>
</body>
</html>

 

 

 

  • MemberServlet
package servletdb.ex04;

import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/member4")
public class MemberServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}

	private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		
		//가입 버튼 클릭 시 db에 추가하기, 알림창 생성
		response.setContentType("text/html;charset=utf-8");
		MemberDAO dao = new MemberDAO(); //서버에 연결돼있으므로 db 연결 따로 X
		PrintWriter out = response.getWriter();
		String command = request.getParameter("command");
		if (command!=null && command.equals("addMember")){
			String _id = request.getParameter("id"); //_변수는 클라이언트에게 받아온 값
			String _pwd = request.getParameter("pwd");
			String _name = request.getParameter("name");
			String _email = request.getParameter("email");	
			
			MemberVO vo = new MemberVO(); //한명의 회원 정보로 저장, db에 넘김
			vo.setId(_id);
			vo.setPwd(_pwd);
			vo.setName(_name);
			vo.setEmail(_email);
			
			dao.addMember(vo);
			out.print("회원가입이 완료되었습니다");
		}
		
	}
    
}

 

 

 

  • MemberDAO
package servletdb.ex04;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

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

public class MemberDAO {


	private Connection con; //db 연동 객체
	private PreparedStatement pstmt; //sql문 미리 컴파일 후 재사용 //연동, 반복 처리에 유용 //데이터베이스 컬럼 가져올 때 명령어 간결 (?) 
	private DataSource dataFactory; //서버에서 데이터 가져옴
	
	public MemberDAO() {
		try {
			Context ctx = new InitialContext(); //서버의 컨텍스트 정보 가져오기 위해 연결
			Context envContext = (Context) ctx.lookup("java:/comp/env"); 
			dataFactory = (DataSource) envContext.lookup("jdbc/oracle"); //미리 연결된 데이터베이스 가져옴
		} catch(Exception e) {
			System.out.println("DB 연결 실패");
		}
	}
	
	//회원정보 목록
	public List<MemberVO> listMembers(){
		List<MemberVO> list = new ArrayList<MemberVO>();
		try {
			con = dataFactory.getConnection(); //서버는 미리 연결된 상태에서 DataSource 이용해 db 연결
			String query = "select * from member_list"; //실행할 쿼리문
			pstmt=con.prepareStatement(query); ////연결하면서 쿼리문 가져와 저장하고 있다가 실행할 때마다 불러옴 (cf. 실행하면서 쿼리문 가져옴)
			ResultSet rs = pstmt.executeQuery();  //미리 설정한 sql문 실행
			while(rs.next()) { //rs => 커서 역할 (검색 결과 집합)
				String id = rs.getString("id"); //컬럼값 하나 가져옴 (1번째, 2번째, ..) //파라미터로 0도 가능(0번째 컬럼)
				String pwd = rs.getString("pwd");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date joinDate = rs.getDate("joindate");
				//데이터타입 숫자일 시 getInt 또는 getDouble
				
				MemberVO vo = new MemberVO(); //위 객체들 담음
				vo.setId(id);
				vo.setPwd(pwd);
				vo.setName(name);
				vo.setEmail(email);
				vo.setJoindate(joinDate);
				
				list.add(vo);
			}
			rs.close();
			pstmt.close();
			con.close();
		} catch (Exception e){
			System.out.println("자료 처리 중 에러 발생");
		}
		return list;
	}//listMembers 끝
	
	//회원 추가
	public void addMember(MemberVO memberVO) {
		try {
			con = dataFactory.getConnection();
			
			String id = memberVO.getId();
			String pwd = memberVO.getPwd();
			String name = memberVO.getName();
			String email = memberVO.getEmail();
			
			String query = "insert into member_list(id, pwd, name, email) values(?,?,?,?)"; //// 
			pstmt=con.prepareStatement(query);
			pstmt.setString(1, id); //첫번째 물음표에 id값 대입
			pstmt.setString(2, pwd);
			pstmt.setString(3, name);
			pstmt.setString(4, email);
			pstmt.executeUpdate();
			pstmt.close();
		} catch(Exception e) {
			System.out.println("회원 추가 중 에러 발생");
		}
	}
	
}