Node.js

[NodeJS] express+mysql2+transaction 데이터 처리

SongMinu 2022. 3. 15. 12:16
728x90

맥북에 mysql 5.7 설치 후 진행했습니다.

connection pool 생성 후 트랜잭션을 이용해 정상 처리시 commit을 에러시 rollback을..

 

커넥션풀 생성

const mysql = require('mysql2/promise');

const {
  MYSQL_HOST,
  MYSQL_USER,
  MYSQL_PW,
  MYSQL_DB,
} = process.env;

module.exports = mysql.createPool({
  host: MYSQL_HOST,
  user: MYSQL_USER,
  password: MYSQL_PW,
  database: MYSQL_DB,
  connectTimeout: 5000,
  connectionLimit: 30 //default 10
})

 

먼저 데이터 insert

router.post('/insert', async (req, res) => {
  let rt = {
    ok : false,
    msg : '',
    result : null
  }
  const params = req.body;
  let conn = null;
  try {
    if (params.user_id === undefined || params.user_id === '') throw { message : '아이디 없음'};
    if (params.user_nm === undefined || params.user_nm === '') throw { message : '이름 없음'};
    if (params.user_pw === undefined || params.user_pw === '') throw { message : '패스워드 없음'};
    const sql = `INSERT INTO ${table} (user_id, user_nm, user_pw, user_addr, user_mk_dt, user_upd_dt, is_use) VALUES (
      "${params.user_id}",
      "${params.user_nm}",
      "${encryptPassword(params.user_pw)}",
      "${params.user_addr}",
      NOW(),
      NOW(),
      1
      )`;
    conn = await mysql.getConnection();
    //트랜잭션 시작
    await conn.beginTransaction();
    const [ rows ] = await conn.query(sql);
    rt.ok = true;
    rt.msg = 'ok';
    rt.result = rows;
    await conn.commit(); //commit
    conn.release();
  } catch (err) {
    console.error('userTable/insert Error!!', err);
    rt.msg = 'user_insert Error';
    rt.result = err.message;
    if (conn !== null) {
      await conn.rollback(); //rollback
      conn.release();
    }
  }
  res.send(rt);
})

데이터 update

router.post('/update', async (req, res) => {
  let rt = {
    ok: false,
    msg: '',
    result: null
  }
  const params = req.body;
  let conn = null;
  try {
    let sql = `UPDATE ${table} SET `;
    //---------------
    let tmp = [];
    if (params.user_nm) {
      tmp.push(`user_nm="${params.user_nm}"`);
    }
    if (params.user_pw) {
      tmp.push(`user_pw="${params.user_pw}"`);
    }
    if (params.user_addr) {
      tmp.push(`user_addr="${params.user_addr}"`);
    }
    //--------------
    if (tmp.length == 0) {
      throw { message : '입력된 값이 없음'};
    } else {
      sql += `${tmp.toString()} WHERE user_id="${params.user_id}"`;
      conn = await mysql.getConnection();
      await conn.beginTransaction();
      const [ result ] = await conn.query(sql);
      rt.ok = true;
      rt.msg = 'ok';
      rt.result = result;
      await conn.commit();
      conn.release();
    }
  } catch (err) {
    console.error('userTable/updae Error!!', err);
    rt.msg = 'user_update Error';
    rt.result = err.message;
    if (conn !== null) {
      await conn.rollback();
      conn.release();
    }
  }
  res.send(rt);
})

업데이트의 경우 변경하고자 하는 필드=값이 입력된 것만 수정하기 위해 위에 처럼 작성함.

스트링을 배열에 담고 해당 변수를 .toString() 하면 콤마 처리까지 깔끔하게 됨.

 

데이터 delete

router.post('/delete', async (req, res) => {
  let rt = {
    ok: false,
    msg: '',
    result: null
  }
  const params = req.body;
  let conn = null;
  try {
    if (params.user_id === undefined || params.user_id === null || params.user_id === '') {
      throw { message : 'parameter user_id is null....'};
    }
    const sql = `DELETE FROM ${table} WHERE user_id="${params.user_id}"`;
    conn = await mysql.getConnection();
    await conn.beginTransaction();
    const [ result ] = await conn.query(sql);
    await conn.commit();
    conn.release();
    rt.ok = true;
    rt.msg = 'ok';
    rt.result = result;
  } catch (err) {
    console.error('userTable/delete Error!!', err);
    rt.msg = 'userTable/delete Error';
    rt.result = err.message;
    if (conn !== null) {
      await conn.rollback();
      conn.release();
    }
  }
  res.send(rt);
})

 

추가 내용.

계속 사용하다보니 쿼리를 짜고 커넥션 -> 트랜잭션 -> 쿼리실행  -> 커밋 -> 릴리즈 이런게 소스에서 계속 반복되다보니 기능하나 만들때마다 코드가 길어지고 중복되는 소스가 너무 많았다.

쿼리만 받아서 위 과정을 처리해서 정상처리 되면 결과를, 실패하면 에러를 반환시키는 함수 하나를 만들어서 함수만 쓰는 게 좋을 것 같다는 생각이 들어서 함수를 아래 처럼 만들어줬다.

//runQuery.js
const mysql = require('../../mysql');

function runQuery(sql) {
  return new Promise( async (resolve, reject) => {
    let conn = null;
    try {
      conn = await mysql.getConnection();
      await conn.beginTransaction(); //트랜잭션 시작
      const [ result ] = await conn.query(sql);
      await conn.commit(); //커밋
      conn.release();
      resolve(result);
    } catch (err) {
      if (conn !== null) {
        await conn.rollback(); //롤백
        conn.release();
      }
      reject(err);
    }
  })  
}

module.exports = runQuery;

프라미스 함수로 만들어서 쿼리를 받고 실행 해서 정상이면 resolve로 에러가 발생하면 reject를 주도록 만들어줬다.

실패 시 내부에서 자체적으로 롤백과 릴리즈까지 하게 작성했다.

그리고 사용은 아래 처럼 했다.

const run = require('./runQuery');

router.post('/insert', async (req, res) => {
  let rt = {
    ok : false,
    msg : '',
    result : null
  }
  const params = req.body;
  try {
    if (isNull(params.user_id)) throw { message : '아이디 없음'};
    if (isNull(params.user_nm)) throw { message : '이름 없음'};
    if (isNull(params.user_pw)) throw { message : '패스워드 없음'};
    const sql = `INSERT INTO ${table} (user_id, user_nm, user_pw, user_addr, user_mk_dt, user_upd_dt, is_use) VALUES (
      "${params.user_id}",
      "${params.user_nm}",
      "${encryptPassword(params.user_pw)}",
      "${params.user_addr}",
      NOW(),
      NOW(),
      1
      )`;
    rt.ok = true;
    rt.msg = 'ok';
    rt.result = await run(sql);
  } catch (err) {
    console.error('userTable/insert Error!!', err);
    rt.msg = 'user_insert Error';
    rt.result = err.message;
  }
  res.send(rt);
})

맨 위에 있는 insert 부분을 수정한 부분이고, 쿼리 실패시 롤백도 함수에서 실행하기 때문에 사용하는 곳에선 try/catch로 받게 구성만 하고 쿼리만 넘겨주면 된다.

반응형