반응형

_웹에서 DB사용하려면.zip
2.05MB

 

환경설정이 중요하다.

프로젝트 생성

 

 

 

구성이 Oracle SQL에서 만들었던 test가 보인다.

 

 

여기에 파일을 넣어주는 이유는, 원래는 Tomcat 서버에 Context 환경설정 파일이 저장되는데, 프로젝트나 파일이 변경될 때 마다, 수정을 해줘야한다. (삭제하기 때문에) 그것이 번거롭기 때문에 META-INF 파일에 넣어서 수시로 넣을 필요없이 한 번의 행위로 끝내는 것이다.

원래는 Tomcat 서버안에 있는 xml Context 부분에 환경설정 파일을 지정해줘야 하는데, 프로젝트나 파일 변경시, 항상 초기화 되서 매우 번거로움.

 

 

 

 

 

 

웹 프로그램은 연결하는데 시간을 단축시켜서 서비스 속도를 빠르게 하기 위해 DBCP를 사용한다.

Connection 한 두개면 웬만한 쇼핑몰 운영이 되지만, 처음 20개를 부여해주게 되는데, 엄청난 데이터 Connection 숫자인것이다.

DataSourceFactory는 컨넥션이 필요할 때 주고 관리한다.

프로그램 시작 할 때 만들어진다.

<?xml version="1.0" encoding="UTF-8"?>
<Context>
	<Resource 
	        auth="Container" 
      		name="jdbc/oracle_test"
      		type="javax.sql.DataSource"
      		driverClassName="oracle.jdbc.driver.OracleDriver"
      		factory="org.apache.commons.dbcp.BasicDataSourceFactory"
      		url="jdbc:oracle:thin:@localhost:1521:xe"
      		username="test" password="1234" 
      		maxActive="20" maxIdle="10" maxWait="1"/>
</Context>

 

 

이 정보를 이용해서 팩토리가 BasicDataSource를 만들어놓는다.

그러면 Oracle은 Connection을 20개 연결해놓는다.

DAO가 컨넥션이 필요할 때 만들어져있지 않고, Oracle에 데이터베이스를 직접가져온다면, 검증이 안되고 시간이 오래걸린다. 컨넥션을 Oracle에 직접 요청하게 되면, 연결지연이 일어날 가능성이 생긴다.

서비스 요청자는 그 지연된 시간만큼 기다려야한다.

하지만, BasicDataSourceFactory로 이미 만들어져있어서 BasicDataSource 창고에 저장이 되어 있기 때문에 바로바로 데이터베이스를 제공해줄 수 있는 것이다.

ex) ㄱ 김밥 집이 있는데, 김밥을 미리 안말고, 손님이 주문할 때 마다 일일이 김밥을 만든다.

1명이 만드는데 1분, 10명이 들이닥치면, 10분이 걸리게 된다. 100명은 100분.. 1명당 1분씩추가..

ㄷ 김밥 집이 있는데, 그 김밥집은 미리미리 김밥을 말아놓는다. 그래서, 손님이 올 때 그 즉시, 기다리지 않고 바로 김밥을 아주머니가 주신다. BasicDataSourceFactory가 ㄷ 김밥집처럼 운영하는셈이다.

 

 

 

DBCP는 BasicDataSource(class)를 관리하는 객체이다. DataSource는 인터페이스가 된다.

DataSource는 설명서이다.  톰켓이 이 자원을 만들어 놓으면, 자원에 대한 이름을 정해놓는다.

이 name을 통해서 JNDI라는 기술을 통해서 만들어진 자원의 인터페이스를 추출한다.

전에는 DBService를 통해서 직접적으로 Oracle에게 데이터베이스를 받아왔다.

DataSource에 대한 인터페이스를 가져오기 위해서 자원에 대한 name을 통해서 검색하는 기술을 JNDI라고 한다. (getConnection을 통해서 미리 만들어져있던 데이터소스를 가져온다.)

 

 

 

 

 

 

 

collections  : ArrayList로 BasicDataSource를 관리한다. (동적으로 들어갔다 나갔다 할 수 있는 자료구조) 항상 20개를 유지해야하는데, close()를 하지 않으면, 컨넥션을 계속 사용한다고 판단하기 때문에, 21번째 요청하는 사람은 채워넣지 않아서 오류가 발생한다. 다 썼으면 close()해서 닫아놓자.

dbcp : oracle과 서로 주고받는다

pool : 풀장(공간)

 

 

 

test/test로 수정

 

 

 

 

 


 

 

 

싱글톤 생성

 

인터페이스 추가

 

컨텍스트 정보 얻어오기

 

package service;

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

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

public class DBService {
	
	// single-ton pattern : 객체 1개만 생성해서 사용하자
	static DBService single = null;
	DataSource ds = null;

	public static DBService getInstance() {
		// 없으면 생성해라
		if (single == null) {
			single = new DBService();
		}
		return single;
	}

	private DBService() {
		
		try {
			// JNDI를 이용해서 DataSource정보를 얻어온다
			// 1. InitialContext 생성(JNDI->interface 추출객체)
			InitialContext ic = new InitialContext();
			
			// 2. Context정보 얻어온다(look up 함수가 Object랑 연관되어 있어서 Casting 해주었음)
			Context context = (Context) ic.lookup("java:comp/env");
			
			// 3. naming을 이용해서 DataSource 얻어온다
			ds = (DataSource) context.lookup("jdbc/oracle_test");
			
			// 2+3 한번에
			// ds = (DataSource) ic.lookup("java:comp/env/jdbc/oracle_test");
			
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}//end:DBService()
	
	public Connection getConnection() throws SQLException {
		// DataSource를 이용해서 BasicDataSource가 관리하고 있는 Connection을 요청
		return ds.getConnection();
	}
	
}

 

 

 

close()하지 않으면, Connection의 수량이 20개가 제한이기 때문에, 20번 작동하면, 오류가 발생한다.

<%@page import="service.DBService"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	Connection conn = DBService.getInstance().getConnection();
	System.out.println("--success--");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

 

 

select * from dept 를 한 번 해보자

 

 

 

 

deptVo 생성하기

package vo;

// 3개가 무조건 일치해야 한다.
// DB Column명 == VO 속성명 == form parameter명

public class DeptVo {
	
	int deptno;
	String dname;
	String loc;
	
	public int getDeptno() {
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
	
}
package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import db.vo.DeptVo;
import service.DBService;

// DAO(Data Access Object)
// Create : insert 추가
// Read : select 조회
// Update : update 수정
// Delete : delete 삭제

public class DeptDao {
	
	// single-ton pattern : 객체 1개만 생성해서 사용하자
	static DeptDao single = null;

	public static DeptDao getInstance() {
		// 없으면 생성해라
		if (single == null) {
			single = new DeptDao();
		}
		return single;
	}

	private DeptDao() {

	}
	
	// import 정리 : ctrl + shift + o
	
	// 부서조회
	public List<DeptVo> selectList() {
		List<DeptVo> list = new ArrayList<DeptVo>();

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		String sql = "select * from dept";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. ResultSet 얻어오기(킵해놨던 sql문 출력하기)
			rs = pstmt.executeQuery();

			while (rs.next()) {
				// 1. rs가 가리키는 레코드의 값을 읽어온다

				// 2. 저장객체 생성 -> 레코드에서 읽은 값을 넣는다.
				DeptVo vo = new DeptVo();

				// rs가 가리키는 레코드값을 VO에 넣는다.
				vo.setDeptno(rs.getInt("deptno"));
				vo.setDname(rs.getString("dname"));
				vo.setLoc(rs.getString("loc"));

				// ArrayList에 추가
				list.add(vo);

			}

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return list;
	}
}

 

 

무족건 Servlet부터 실행하기

 

Servlet 작성하기

package action;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

import dao.DeptDao;
import db.vo.DeptVo;

/**
 * Servlet implementation class DeptListAction
 */
@WebServlet("/dept/list.do")
public class DeptListAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 부서데이터 가져오기(DeptDao -> DBService)
		List<DeptVo> list = DeptDao.getInstance().selectList();
		
		// request binding(list에 가져온 데이터 request에 저장)
		request.setAttribute("list", list);
		// 이로써, 현재 이 class와 dept_list와 list가 공유되어 있다.

		// Dispatcher형식으로 호출
		//                    webapp/dept/폴더내에 dept_list.jsp 생성
		String forward_page = "dept_list.jsp";
		RequestDispatcher disp = request.getRequestDispatcher(forward_page);
		disp.forward(request, response);

	}

}

 

 

해당 경로에 jsp 만들어주기(데이터 출력화면)

 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<style type="text/css">
	#box {
		width: 600px;
		margin: auto;
		margin-top: 50px;
	}
	
	table {
		border: 2px solid blue !important;
	}
</style>
</head>
<body>

	<div id="box">
		<table class="table table-bordered table-hover">
			<tr class="success">
				<th>부서번호</th>
				<th>부서명</th>
				<th>위치</th>
			</tr>
			<!-- DeptListAction와 request의 데이터 창고가 공유되어 있다. -->
			<!-- for(DeptVo vo : list) 동일함. -->
			<c:forEach var="vo" items="${ requestScope.list }">
			<tr>
				<td>${ pageScope.vo.deptno }</td>
				<td>${ vo.dname }</td>
				<td>${ vo['loc'] }</td>
			</tr>
			</c:forEach>
			
		</table>
	</div>

</body>
</html>

 

 

반응형