파라미터 값 받기

ex03_form.jsp

 

입력 받은 값을 출력 ( jstl 문법으로 param."파라미터 이름" 또는 여러개의 파라미터 값이면 paramValues."파라미터 이름" 으로 불러온다

 

코드 실행 결과

 

 

 

 

 

DAO, DTO 활용하기

TestDAO.java, TestDTO.java 파일 생성 후 작성

 

ex04_all_data.jsp, ex04_one_date.jsp 작성 ( bean 객체를 사용하여 TestDAO 에 있는 데이터를 dao 라는 변수로 저장 > dao 의 getList() 메소드를 사용하여 얻어지는 값들을 list 변수에 저장 > 해당 list 를 for Each 문을 사용하여 dto 라는 변수로 받아서 사용

728x90

 

 

 

 

 

EL

EL

 

EL 연산자

 

EL 의 출력방법, jstl 의 if 문, 반복문은 Spring 에서도 사용되니 기억하기 !!!

 

파일 세팅

 

파일 세팅 완료, 미리 ojdbc8.jar 도 세팅함

 

EL 문법의 ${} 는 자바스크립트에서 사용하는 표현 문법인 ${} 과 같이 사용할 수 없다

( jsp 파일에서는 자바스크립트의 ${} 를 사용할 수 없음 )

 

ex01.jsp 에 EL 문법의 단순 출력식 표현 > 결과물

 

EL 연산

 

login.jsp 에 로그인 폼 간단히 작성, result.jsp 에서는 기존 파라미터 값 받아오는 코드와 el 문법으로 파라미터 값을 받아오는 코드 작성

 

 

 

 

 

EL scope

파일 세팅

 

set.jsp 와 get.jsp 를 작성 과 결과물

 

 

 

 

 


 

 

 

 

 

JSTL

 

Apache Taglibs - Apache Standard Taglib: JSP[tm] Standard Tag Library (JSTL) implementations

<!-- Copyright 1999-2011 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/

tomcat.apache.org

JSTL 다운로드 사이트

 

jakarta-taglibs-standard-1.1.2.zip 다운로드

 

다운로드 받은 zip 파일 압축 해제 후 lib 폴더에 있는 jstl.jar 파일과 standard.jar 파일 복사하여 프로젝트 내 lib 파일에 붙여넣기

 

파일 세팅

 

파일 세팅 완료

 

JSTL 이란?

 

JSTL 태그

 

JSTL core 기능

 

JSTL 문법을 사용하려면 taglib 으로 jstl 의 core 를 불러와서 c 라는 이름으로 사용한다고 정의해줘야 한다

 

JSTL 문법

 

forEach 문 사용과 forTokens 를 사용해서 특정 문자를 기준으로 잘라서 표현

 

예외처리 ( catch 문 안에 내용이 예외를 발생시킨다면 해당 예외를 result 라는 변수에 담는다 )

 

Scope 정의 및 확인 ( import 로 ex02_test.jsp 파일의 내용을 불러옴 include 와 같은 역할 )

 

ex02_delete.jsp 에서 세션을 삭제하고 다시 ex02_session.jsp 로 리다이렉트로 보냄

 

다양한 절대경로의 표현 방식

 

코드 실행 영상
728x90

 

 

 

 

 

액션 태그

jsp 액션 태그

 

 

 

 

 

forward 태그

파일 세팅

 

파일 세팅 완료

 

login.jsp 작성

 

check.jsp 에 로그인 실패 시 코드 작성

sendRedirect() : 클라이언트에게 주소를 전송한 뒤 클라이언트가 서버에 전달받은 주소를 다시 요청

forward() : 클라이언트에게 주소를 요청하지 않고 서버에서 처리하여 내부의 경로를 출력

 

액션 태그를 사용하여 로그인 성공 시 코드 작성

 

main.jsp 에서는 request 값이 forward 로 넘어와서 scope 의 범위 내에서 작동하기 때문에 id 와 msg 파라미터를 페이지가 이동되었음에도 사용할 수 있다.

 

 

 

 

 

include 태그

파일 세팅

 

파일 세팅 완료

 

ex01.jsp 작성

 

jsp_include.jsp 와 tag_include.jsp 를 작성

 

각각 jsp 액션 태그와 기본 태그를 사용하여 작성

 

ex01.jsp 에 변수 생성 후 각 페이지에서 확인

>> jsp 액션 태그를 사용해서는 include 로 가져온 변수를 사용할 수 없다. ( 기존 태그를 사용해야 함 )

 

 

 

 

 

useBean 태그

파일 세팅

 

create table mem_jsp(
id varchar2(20) primary key,
pwd varchar2(20),
name varchar2(20),
addr varchar2(100),
tel varchar2(20)
);

insert into mem_jsp values('aaa','aaa','홍길동','산골짜기','010-xxx-xxx');
insert into mem_jsp values('bbb','bbb','김개똥','개똥별','010-xxx-xxx');
insert into mem_jsp values('ccc','ccc','고길똥','마포구','010-xxx-xxx');

commit;

sql 문 실행

 

파일 세팅 완료

 

MemberDTO.java 에 DB 에 저장된 데이터 형식 선언 후 getter / setter 생성

 

ex01.jsp 에서 bean 객체에 DTO 객체를 담아 setter 를 이용해 값을 저장하고 getter 를 이용해 불러와 출력

 

register_form.jsp 에 작성

 

register.jsp 에 기존 방식으로 저장하여 사용하는 코드 작성

 

register_form.jsp 에 넘어온 값들을 setProperty 로 한꺼번에 DTO 에 저장 후 각 값에 1 기입 후 전송

단, setProperty 를 이용해서 bean 객체에 저장할때 넘어오는 이름과 DTO 의 변수 이름이 동일해야 한다

 

index.jsp 파일 작성

 

register_form.jsp 와 show_list.jsp 파일에 index.jsp 를 include

 

MemberDAO.java 에 DB 연동 코드 작성

 

ojdbc8.jar 추가

 

show_list.jsp 에 MemberDAO 를 객체화하여 실행시킨 뒤 콘솔창에 --- 드라이브 로드 성공 --- 문구가 출력되면 정상적으로 DB 에 연동되었다는 의미

 

jsp 태그로 bean 객체를 만들어 memberDAO 를 객체를 생성

 

MemberDAO.java 파일에 DB 에서 mem_jsp 테이블의 정보를 DTO 에 담아서 return 하는 getList() 메소드 선언

 

이후 show_list.jsp 에서 이 getList() 메소드를 사용하여 list 변수에 담고 해당 list 사이즈를 출력하면 콘솔 창에 DB 에 저장된 행의 갯수인 3이 출력됨

 

가져온 값을 table 에 출력

 

register.jsp 에 DB 에 회원을 추가하는 코드를 추가

 

MemberDAO.java 에 DB 에 데이터를 저장하는 register 메소드를 정의

 

회원가입 이후 DB 에 저장된 모습 바로 확인됨

728x90

 

 

 

 

 

DB 연동

파일 세팅, ojcbc8 도 lib 폴더에 넣어놔야 함

 

create table member_jsp(
id varchar2(20) primary key,
name varchar2(20),
kor number,
eng number,
math number
);
insert into member_jsp values('aaa','Hong',100,100,100);
insert into member_jsp  values('bbb','Kim',90,90,90);
insert into member_jsp  values('ccc','Go',80,80,80);

commit;

sql 문 실행

 

driver.jsp 작성, 연동 성공 문구 콘솔창에 출력되어야 DB 연동 성공 ( 11 버전 : xe, 이후 버전 : orcl )

DriverManager 와 Connection 클래스 import 필요

 

select_all.jsp 에서 driver.jsp 파일을 include 해서 con 객체를 받아와서 출력 및 각 name 에 a 태그 추가

 

쿼리문 실행 결과를 담은 ResultSet 의 구성 rs.next() 를 사용하여 다음 값이 있는지 확인

 

select_all.jsp 페이지에서 이름을 클릭했을때 a 태그로 파라미터 값과 함께 전달되는 것 select_one.jsp 에서 확인

 

select_all.jsp 에서 넘겨받은 파라미터 값을 가지고 select_all.jsp 에서 DB 에 접근하여 내용을 표시

728x90

 

 

 

 

 

response

ex01.jsp 를 실행하면 응답으로 redirect 가 실행되어 네이버가 출력

 

파일 3개 세팅 check.jsp, login.jsp, main.jsp

 

login.jsp, check.jsp, mian.jsp 작성

 

getWriter() 메소드를 사용하여 script 를 이용해 alert 창을 띄울 수도 있다

 


 

 

 

 

Scope

Scope

 

파일 세팅

 

set_scope.jsp 에서 scope(page, request, session, application) 를 생성, scope 생성 시 괄호의 앞 내용은 키 뒷 내용은 값이다.

 

page : 요청한 페이지 내에만 유지 ( 페이지가 이동되면 삭제 )

request : 요청한 페이지에서 다음 페이지까지 유지된다

session : 현재 켜져있는 브라우저에서만 작동 ( 예를 들어, 크롬에서 scope 를 받고 네이버 웨일로 동일 웹을 작동시키면 session 이 유지되지 않음, 주로 로그인에서 사용 )

application : 작동하는 브라우저를 변경해도 application 은 유지되며 서버가 종료되면 application 도 삭제

 

request 를 다음페이지 까지 유지하고 싶으면 forward 를 사용하여 전달 받은 request 값을 전달해야 한다.

이런 식으로 전달하지 않으면 페이지를 임의로 이동시킨다고 해서 scope 가 다음 페이지까지 저장된 상태로 넘어가지 않는다.

 

 

 

 


 

 

 

 

 

cookie

쿠키 : 클라이언트에서 관리

파일 세팅

 

쿠키 생성

testCookie 라는 key 로 myCookie 라는 내용을 생성, cookie.setMaxAge(5) 로 5초동안 쿠키를 유지

 

스크립트를 사용하여 팝업창을 출력하게끔 설정

 

popup.jsp 간단히 작성

 

요청으로 부터 getCookies() 메소드를 사용해 쿠키의 목록을 Cookie 자료형의 배열로 받아와서 출력

 

최초 요청시에는 기본 발급 쿠키만 존재하지만 5초 내에 새로고침을 하여 요청을 다시 보내면 쿠키 값을 출력한다

 

testCookie 라는 이름의 쿠키가 없을때만 팝업을 출력 ( boolean 값으로 조절 )

 

test.jsp 파일 추가

 

ex01.jsp 에서는 test.jsp 경로로 가는 a 태그를 추가, test.jsp 에서는 현재 쿠키 값을 보여주는 코드를 작성

 

테스트 해보면 cookie 는 발급된 파일의 상위 파일이 실행될때는 존재하지 않는다.

자신의 상위 파일이 실행될때도 쿠키값을 존재하게 하려면 cookie.setPath() 메소드를 사용하여 쿠키의 경로를 설정해줘야 한다.

 

쿠키를 최상위 위치에서 부터 쿠키를 사용할 수 있게 설정 후 쿠키가 정상적으로 확인

 

ex01.jsp 에 쿠키 삭제 경로 추가

 

쿠키는 삭제하는 코드가 따로 없기 때문에 쿠키의 유지 시간을 0초로 조정하여 응답하여 삭제시킨다

※ 쿠키는 삭제하는 코드가 따로 없기 때문에 쿠키의 유지 시간을 0초로 조정하여 응답하여 삭제시킨다

 

 

 

 

 


 

 

 

 

 

session

세션 : 서버에서 관리

파일 세팅

 

set.jsp 에서 세션 설정, get.jsp 에서 세션 출력

 

del.jsp 에서 세션 삭제

 

session.removeAttribute("age") : age 라는 키의 세션을 삭제시킨다.

session.setMaxInactiveInterval(5) : 5초 후 모든 세션을 만료시킨다.

session.invalidate() : 모든 세션을 만료시킨다.

 

간단하게 login.jsp 에 입력받는 폼 작성

 

로그인 정보를 검증하는 check.jsp 작성

 

main.jsp 작성

 

logout.jsp 작성

 

세션으로 로그인을 관리하는 페이지 작성 완료

728x90

 

 

 

 

 

JSP

 

이클립스 다운로드

 

Eclipse Packages | The Eclipse Foundation - home to a global community, the Eclipse IDE, Jakarta EE and over 350 open source pro

520 MB 197,629 DOWNLOADS Tools for developers working with Java and Web applications, including a Java IDE, tools for JavaScript, TypeScript, JavaServer Pages and Faces, Yaml, Markdown, Web Services, JPA and Data Tools, Maven and Gradle, Git, and more. Cli

www.eclipse.org

 

Eclipse Enterprise 버전 다운로드 ( 웹을 구동해야 하므로 Enterprise 버전이 필요한다 )

 

 

 

 

 

 

아파치 톰캣 9 버전 다운로드

 

Apache Tomcat® - Apache Tomcat 9 Software Downloads

Welcome to the Apache Tomcat® 9.x software download page. This page provides download links for obtaining the latest version of Tomcat 9.0.x software, as well as links to the archives of older releases. Unsure which version you need? Specification version

tomcat.apache.org

 

64-bit Windows zip 버튼 눌러서 다운로드 및 압축 해제

 

압축 해제 완료

 

 

 

 

 

워크스페이스 생성 및 설정

 

프로젝트 생성

 

New Runtime 클릭

 

Apache Tomcat v9.0 클릭, Create a new local server 체크 후 Next

 

아파치 톰캣 설치된 경로를 설정 > Browse 클릭

 

아파치 톰캣 설치 경로까지 들어가 폴더 선택 클릭

 

Finish 클릭

 

src - main - webapp 하위에 ex01.jsp 생성 후 body 태그 안에 문자 작성 후 저장하여 웹 테스트

 

Ctrl _ F11 눌러서 실행시킨 뒤 서버를 톰캣으로 실행, Always use this server when running this project 클릭 후 Finish

 

웹 정상 실행

 

 

 

 

 


▼ 만약 서버를 실행시켰는데 에러가 출력된다면 사용하려는 포트 번호가 겹친 경우!! ▼

포트번호가 겹쳐 에러가 발생한다면 하단의 servers 탭에 현재 구동중인 Tomcat v9.0 서버 더블클릭

 

HTTP/1.1 포트 번호가 겹쳐서 문제가 발생하는 것이기 때문에 포트번호를 8080에서 변경해준다


 

 

 

 

 

인코딩 방식 변경

한글을 처리하기 위해서 charset 을 UTF-8 로 변경해야 함
Window - Preferences - General - Workspace 의 Other 항목이 UTF-8 로 선택되어 있는지 확인

 

Web - CSS Files - Encoding 을 UTF-8 로 변경

 

HTML Files 도 인코딩 방식 UTF-8 로 변경

 

JSP Files 도 인코딩 방식 UTF-8 로 변경

 

위 설정 이후 새로 jsp 파일을 생성하면 자동으로 인코딩 방식이 UTF-8 로 변경되어 생성된다

 


 

 

 

 

 

JSP 기본 태그

JSP 기본 태그

 

 

 

 

 

스크립트릿

스크립트릿 > 실행하면 웹이 실행되며 콘솔창에 num : 100 이 출력 > 웹에는 따로 출력한 것이 없기 때문에 빈 페이지가 출력됨

 

스크립트릿 > out.print(); 함수를 사용하여 웹에도 출력

 

 

 

 

주석

<%-- --%>

 

 

 

 

 

표현식

<%= %>

 

스크립트릿과 표현식 함께 사용

 

 

 

 

 

선언문

<%! %> : 서버가 실행될때 처음 한번만 확인.... 그래서 num++ 를 입력한 뒤 새로고침하면 num 의 수가 계속 올라감 ( 서버 재실행 시 초기화 )

 

메소드는 선언문에서만 생성할 수 있다!

 

선언문 사용 예시 ( HashMap 입력 후 Ctrl + Spacebar 눌러서 import 후 실행 )

 

 

 

 

지시자

( 아래서 자세하게 다룸 )

 


 

 

 

 

 

경로 이동 방식

 

새로운 dynamic web project 생성

파일 생성

 

절대경로와 상대경로 사용 방식

각각 상대경로, 절대 경로를 사용하여 각 jsp 파일로 a 태그를 사용하여 경로 변경

 

 

 

 

 

Get 방식, Post 방식

Request & Response

 

파일 세팅

 

form.jsp 작성

 

get.jsp, post.jsp 작성

 

post 방식으로 넘기면 request.setCharacterEncoding("utf-8") 로 인코딩 방식을 명시해줘야 한글이 깨지지 않는다.

!!! post 방식으로 값을 넘길땐 받는 쪽에서 인코딩 방식을 꼭 명시해주기 !!!

 

form2.jsp 와 result.jsp 파일 생성 및 작성

 


 

지시자

지시자

 

 

 

 

 

page 지시자

파일 생성

 

ex02.jsp 에서 값을 0 으로 나눠서 에러 발생시킨 뒤 <%@ %> 사용하여 에러페이지를 error_msg.jsp 로 설정

 

error_msg.jsp 에서는 isErrorPage 를 true 옵션으로 바꿔 에러페이지 파일임을 명시해줘서 exception 을 사용하여 에러 메세지를 출력할 수 있다.

 

 

 

 

 

include 지시자

파일 세팅

 

header.jsp 와 footer.jsp 파일 작성

 

main.jsp 작성 ( header.jsp 와 footer.jsp 를 불러와서 사용 )

 

 

 

 

 

taglib 지시자

 

 

 

 

 

 

 

 

 

 

 

 

 

 

실습 예제

실습 예제

 

예제 풀이

header.jsp ( 각각 파일의 디렉토리가 다르므로 절대 경로를 사용 )

 

main.jsp

 

ex01.jsp

 

ex02.jsp 는 에러가 발생하는 페이지 이므로 error_msg.jsp 에 include 태그 적용

 


 

 

 

 

 

Request / Response

파일 세팅

 

ex02_form.jsp 작성 ( request.getContextPath 를 사용해서 프로젝트의 경로를 받아와서 사용 )

 

ex02_result.jsp 에서 여러 파라미터 값이 같은 name 으로 넘어오는 경우 request.getParameterValues 를 사용하여 문자열 배열로 받아서 사용한다.

 

getParameterNames 를 사용하여 파라미터의 이름을 확인....

반환형태는 Enumeration<String> 형태이며 while 문을 사용하여 다음 내용이 있는지 확인하여 nextElement() 메소드를 사용하여 변수로 해당 파라미터명을 담아서 사용한다.

728x90

 

 

 

 

 

비트코인 모의 투자를 구현하는 와중 실시간으로 데이터를 업비트 api 를 통해 가져와 Oracle Cloud DB 에 저장하고 해당 데이터를 꺼내 실시간으로 가격을 비교해서 출력해야 하는 과정이 필요했다.

 

문제 발생 : DB 안에 1초마다 쌓이는 각 코인들의 값을 select 쿼리로 1초마다 가져올때 ( 자바스크립트의 setInterval 메소드를 사용하여 Oracle Cloud DB 로 1초마다 데이터를 요청 ) Error: NJS-500: connection to the Oracle Database was broken 문구가 발생되면서 값을 제대로 가져오지 못하는 현상이 발생, 로그인 시도 시에도 동일한 현상이 발생

 

총 평가 금액을 실시간으로 localhost:3000/wallet/total_buy_coin_result_cost 경로로 요청하는 함수
ejs 파일 내에서 위 함수를 1초마다 갱신

 

위 구문을 실행하면 서버에서 DB 에 접근하여 데이터를 받아오게끔 설계해 놨는데 아래가 해당 dao 의 코드이다

 

const oracledb = require("oracledb");
const dbConfig = require("../../../config/database/db_config");
oracledb.outFormat = oracledb.OBJECT;
oracledb.autoCommit = true;

const get = {
    have_KRW : async (member_id) => {
        const con = await oracledb.getConnection(dbConfig);
        let result = await con.execute(`select money from member where member_id='${member_id}'`);
        return result;
    },
    // 매수했던 각 코인의 갯수를 Object 형태로 담는 함수
    had_coin_num : async (member_id) => {
        let had_coin_num = {
            btc : 0,
            eth : 0,
            shib : 0,
            bch : 0,
            etc : 0,
            btg : 0,
            sol : 0,
            doge : 0,
            xrp : 0,
            id : 0,
            pundix : 0,
            stx : 0,
            aave : 0,
            dot : 0,
            avax : 0,
            gas : 0,
            sbd : 0,
            ong : 0,
            sei : 0,
            ont : 0
        };
        let coin_list = ["btc","eth","shib","bch","etc","btg","sol","doge","xrp","id","pundix","stx","aave","dot","avax","gas","sbd","ong","sei","ont"];
        const con = await oracledb.getConnection(dbConfig);
        for(let i=0; i<coin_list.length; i++){
            // 구매 코인의 총 갯수를 가진 DB 결과 Object
            let coin_num_object = await con.execute(`select coin_num from trade where coin_name='${coin_list[i]}' and member_id = '${member_id}' and status = 1`);
            
            // 코인의 구매 이력이 없는 경우
            if(coin_num_object.rows[0] === undefined){
                had_coin_num[coin_list[i]] = 0;
                continue;
            }

            let each_coin_num = 0;
            coin_num_object.rows.forEach(coin => {
                if(coin.COIN_NUM == null){
                    coin.COIN_NUM = 0;
                }
                each_coin_num += coin.COIN_NUM;
            })
            had_coin_num[coin_list[i]] = each_coin_num
        }
        return had_coin_num;
    },
    // 매수했던 각 코인의 가격의 합을 Object 형태로 담는 함수
    had_coin_cost : async (member_id) => {
        let had_coin_cost = {
            btc : 0,
            eth : 0,
            shib : 0,
            bch : 0,
            etc : 0,
            btg : 0,
            sol : 0,
            doge : 0,
            xrp : 0,
            id : 0,
            pundix : 0,
            stx : 0,
            aave : 0,
            dot : 0,
            avax : 0,
            gas : 0,
            sbd : 0,
            ong : 0,
            sei : 0,
            ont : 0
        };
        let coin_list = ["btc","eth","shib","bch","etc","btg","sol","doge","xrp","id","pundix","stx","aave","dot","avax","gas","sbd","ong","sei","ont"];
        const con = await oracledb.getConnection(dbConfig);
        for(let i=0; i<coin_list.length; i++){
            // 구매 코인의 총 갯수를 가진 DB 결과 Object
            let coin_cost_object = await con.execute(`select buy_cost from trade where coin_name='${coin_list[i]}' and member_id = '${member_id}' and status = 1`);
            
            // 코인의 구매 이력이 없는 경우
            if(coin_cost_object.rows[0] === undefined){
                had_coin_cost[coin_list[i]] = 0;
                continue;
            }

            let each_coin_cost = 0;
            coin_cost_object.rows.forEach(coin => {
                if(coin.BUY_COST == null){
                    coin.BUY_COST = 0;
                }
                each_coin_cost += coin.BUY_COST;
            })
            had_coin_cost[coin_list[i]] = each_coin_cost
        }
        return had_coin_cost;
    },
    // 현재 보유 중인 코인의 갯수를 구하는 함수
    have_coin_num : async (member_id) => {
        const con = await oracledb.getConnection(dbConfig);
        let have_coin_num = await con.execute(`select btc,eth,shib,bch,etc,btg,sol,doge,xrp,id,pundix,stx,aave,dot,avax,gas,sbd,ong,sei,ont from member_account where member_id = '${member_id}'`);
        return have_coin_num.rows[0];
    },
    // 현재 코인의 가격 20개를 구하는 함수
    now_coin_cost : async () => {
        const con = await oracledb.getConnection(dbConfig);
        let now_coin_cost_object = await con.execute(`select * from (select * from coin_info order by order_column desc) where rownum <= 20`);
        return now_coin_cost_object.rows;
    }
}

module.exports = {get}

위의 코드 중 평가 금액은 현재 보유 중인 코인의 갯수를 구하는 함수와 현재 코인의 가격 20 개를 구하는 함수를 사용하는데, 이 부분을 반복적으로 돌리면 계속 DB의 연결이 끊기는 오류가 발생....

 

 

 

 

 

웹에서 NJS-500 오류 코드와 관련해서 내용을 찾아보다가 문득 DB 에 데이터를 넣는 부분과 DB 의 데이터를 꺼내오는 부분이 동시에 작동하여 문제가 생기지 않을까 하는 생각이 들었다.

( Oracle Cloud DB 와 연결이 끊어질때 1회성 쿼리가 발생됨으로 세션 타임아웃 문제는 아닐 것으로 예상, 고로 최대 연결 갯수의 초과이거나 커넥션의 과부하로 인한 연결 끊김으로 예상 )

 

 

이 부분을 해결할 수 있는 방법을 찾다 보니 커넥션 풀(DBCP) 에 대한 부분이 나왔고 이를 사용해보기로 했다.

 

- 커넥션 풀(DataBase Connection Pool)이란? -

웹 컨테이너(WAS)가 실행되면서 미리 DB 와 연결(connection)된 객체를 pool 에 저장해 두었다가 클라이언트에게 요청이 오면 connection 을 빌려주고 처리가 끝나면 다시 connection 을 반납받아 pool 에 저장하는 방식을 말한다.

 

- 커넥션 풀의 특징 -

1. 웹 컨테이너(WAS)가 실행되면서 connection 객체를 미리 pool 에 생성해 둔다.

2. HTTP 요청이 들어오면 pool 에 저장된 connection 객체를 가져다 쓰고 반환한다.

3. 위 방식으로 물리적인 데이터베이스 connection 부하를 줄이고 연결을 관리한다

( 다중 접속의 경우 커넥션 풀을 사용하게 되면 이미 connection 을 다른 곳에서 사용 중인 경우 사용자는 pool 이 connection 을 반환받아 제공해줄때 까지 대기 상태로 기다린다. )

4. pool 에 미리 connection 이 생성되어 있기 때문에 DB 에 접근할 때마다 connection 을 생성하지 않아 연결 시간이 소비되지 않는다.

 

 

커넥션 풀(DBCP)를 사용한 코드

const oracledb = require("oracledb");
const dbConfig = require("../../../config/database/db_config");
oracledb.outFormat = oracledb.OBJECT;
oracledb.autoCommit = true;

let pool;

async function initialize() {
    try {
        pool = await oracledb.createPool(dbConfig);
        console.log("Connection pool 생성됨");
    } catch (error) {
        console.error("Connection pool 생성 중 오류:", error);
    }
}

initialize();

const get = {
    have_KRW : async (member_id) => {
        let connection;
        try{
            connection = await pool.getConnection();
            let result = await connection.execute(`select money from member where member_id='${member_id}'`);
            await connection.close();
            return result;
        }catch(err){
            console.log(err);
        }
    },
    // 매수했던 각 코인의 갯수를 Object 형태로 담는 함수
    had_coin_num : async (member_id) => {
        let connection;
        try{
            let had_coin_num = {
                btc : 0,
                eth : 0,
                shib : 0,
                bch : 0,
                etc : 0,
                btg : 0,
                sol : 0,
                doge : 0,
                xrp : 0,
                id : 0,
                pundix : 0,
                stx : 0,
                aave : 0,
                dot : 0,
                avax : 0,
                gas : 0,
                sbd : 0,
                ong : 0,
                sei : 0,
                ont : 0
            };
            let coin_list = ["btc","eth","shib","bch","etc","btg","sol","doge","xrp","id","pundix","stx","aave","dot","avax","gas","sbd","ong","sei","ont"];
            connection = await pool.getConnection();
            for(let i=0; i<coin_list.length; i++){
                // 구매 코인의 총 갯수를 가진 DB 결과 Object
                let coin_num_object = await connection.execute(`select coin_num from trade where coin_name='${coin_list[i]}' and member_id = '${member_id}' and status = 1`);
                
                // 코인의 구매 이력이 없는 경우
                if(coin_num_object.rows[0] === undefined){
                    had_coin_num[coin_list[i]] = 0;
                    continue;
                }

                let each_coin_num = 0;
                coin_num_object.rows.forEach(coin => {
                    if(coin.COIN_NUM == null){
                        coin.COIN_NUM = 0;
                    }
                    each_coin_num += coin.COIN_NUM;
                })
                had_coin_num[coin_list[i]] = each_coin_num
            }
            await connection.close();
            return had_coin_num;
        }catch(err){
            console.log(err);
        }
    },
    // 매수했던 각 코인의 가격의 합을 Object 형태로 담는 함수
    had_coin_cost : async (member_id) => {
        let connection;
        try{
            let had_coin_cost = {
                btc : 0,
                eth : 0,
                shib : 0,
                bch : 0,
                etc : 0,
                btg : 0,
                sol : 0,
                doge : 0,
                xrp : 0,
                id : 0,
                pundix : 0,
                stx : 0,
                aave : 0,
                dot : 0,
                avax : 0,
                gas : 0,
                sbd : 0,
                ong : 0,
                sei : 0,
                ont : 0
            };
            let coin_list = ["btc","eth","shib","bch","etc","btg","sol","doge","xrp","id","pundix","stx","aave","dot","avax","gas","sbd","ong","sei","ont"];
            connection = await pool.getConnection();
            for(let i=0; i<coin_list.length; i++){
                // 구매 코인의 총 갯수를 가진 DB 결과 Object
                let coin_cost_object = await connection.execute(`select buy_cost from trade where coin_name='${coin_list[i]}' and member_id = '${member_id}' and status = 1`);
                
                // 코인의 구매 이력이 없는 경우
                if(coin_cost_object.rows[0] === undefined){
                    had_coin_cost[coin_list[i]] = 0;
                    continue;
                }

                let each_coin_cost = 0;
                coin_cost_object.rows.forEach(coin => {
                    if(coin.BUY_COST == null){
                        coin.BUY_COST = 0;
                    }
                    each_coin_cost += coin.BUY_COST;
                })
                had_coin_cost[coin_list[i]] = each_coin_cost
            }
            await connection.close();
            return had_coin_cost;
        }catch(err){
            console.log(err)
        }
    },
    // 현재 보유 중인 코인의 갯수를 구하는 함수
    have_coin_num : async (member_id) => {
        let connection;
        try{
            connection = await pool.getConnection();
            let have_coin_num = await connection.execute(`select btc,eth,shib,bch,etc,btg,sol,doge,xrp,id,pundix,stx,aave,dot,avax,gas,sbd,ong,sei,ont from member_account where member_id = '${member_id}'`);
            await connection.close();
            return have_coin_num.rows[0];
        }catch(err){
            console.log(err)
        }
    },
    // 현재 코인의 가격 20개를 구하는 함수
    now_coin_cost : async () => {
        let connection;
        try{
            connection = await pool.getConnection();
            let now_coin_cost_object = await connection.execute(`select * from (select * from coin_info order by order_column desc) where rownum <= 20`);
            await connection.close();
            return now_coin_cost_object.rows;
        }catch(err){
            console.log(err);
        }
    }
}

module.exports = {get}

initiallize() 함수를 사용하여 애플리케이션 시작 시 connection 정보가 담긴 pool 을 미리 변수로 저장해 놓은 뒤 사용

 

 

 

오류 없이 정상적으로 데이터를 받아오는 모습

 

결론 : DB 에 지속적으로 접근하여 데이터를 받아와야 하는 경우, 혹은 다량의 DB 접속이 발생할 경우에는 connection pool 을 사용하자

 

보완할 점 : Connection pool 을 생성하여 사용할때 유휴 Connection 을 확인하여 커넥션의 갯수를 확보하고, 최대 Connection pool 의 갯수를 지정하여 연결의 수를 제한하여 사용할 것

728x90

 

 

 

 

 

Oracle cloud 의 자율운영 데이터베이스를 free tier 로 구성해서 사용중이었는데....

 

간단한 쿼리문을 처리하는데 DB 처리 속도가 3초 정도 지연되는 현상이 발생되었다....

 

간단한 로그인 과정에도 쿼리문 전송 후 응답이 오래걸리는 모습

 

 

 

 

 

DAO 에 DB 에 연결되는 부분과 쿼리문 전송 및 응답 부분에 console.log 를 찍어 확인

 

 

 

 

 

DB 서버에 접속 자체가 오래걸리는 모습

 

 

 

 

 

아무리 Free Tier 클라우드라지만 DB 접속 속도가 너무너무 느리다....

 

문득, Oracle Cloud 를 생성할때 home region 을 시카고로 설정해둔 것이 문제인가 싶었다

 

내 region 설정 : Chicago

 

검색해보니 region 은 최초에 계정을 생성할때 한번만 설정할 수 있으며, 이후에는 Free Tier 에서는 변경할 수 없다고 한다...

 

결국 다른 계정을 생성하여 region 을 한국의 춘천으로 변경하였더니 DB 접속 속도가 로컬과 다를 바 없이 빨라졌다.

 

 

Oracle Cloud 의 region 변경 후 속도

 

 

 

 

 

- 결론 -

오라클 클라우드 DB 에 접속이 느리다면 현재 region 이 대한민국으로 설정되어 있는지 확인해보자

또한, 오라클 클라우드의 region 은 첫 계정 생성시에 설정한 뒤 이후에 변경하지 못하니 처음부터 대한민국으로 설정해놓자....

728x90

+ Recent posts