본문 바로가기

프로젝트

Oracle Cloud 오류 ( Error: NJS-500: connection to the Oracle Database was broken ) ( 해결 완료 )

 

 

 

 

 

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

 

문제 발생 : DB 안에 1초마다 쌓이는 각 코인들의 값을 select 문으로 1초마다 가져올때 ( frontend 측에서 setInterval 을 사용해서 Script 문 안에서 fetch 로 backend 측으로 1초마다 요청 ) Error: NJS-500: connection to the Oracle Database was broken 문구가 발생되면서 값을 제대로 가져오지 못하는 현상이 발생

 

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

 

위 구문을 실행하면 백엔드 측에서 DB 에 접근하여 데이터를 받아오게끔 설계해 놨는데 아래는 be 측 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 의 데이터를 꺼내오는 부분이 동시에 작동하여 문제가 생기지 않을까 하는 생각이 들었다.

 

 

이 부분을 해결할 수 있는 방법을 찾다 보니 커넥션 풀(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 에 지속적으로 접근하여 데이터를 받아와야 하는 경우는 connection pool 을 사용하자

728x90