Node.js에서 mysql을 async/await으로 작성하기
2018-06-08
Node.js로 코드를 작성하다보면 분명히 한 번 이상은 겪게 되는 비동기 코드 문제.
일명 Callback Hell이라고 불리우는 코드 구조를 본다면 진짜 지옥의 구렁텅이로 빠져드는 것만 같다.
다행히도 여러가지의 비동기 코드를 작성하는 방법이 제시되고는 한다.
몇 가지 예를 들자면 async 라이브러리, ES2015의 기능 Promise, ES2017의 기능 async/await, RxJS 등이 있다.
주로 Promise를 사용했는데 얼마전 사용해본 ES2017의 async/await
가 가장 편한 것 같다.
기존까지는 Mysql DB Connection에 있어서 Promise로 작성하던 것을 async/await
로 싹 바꿨는데 async/await를 활용하는 방법에 대해 잠깐 소개하고자 한다.
설치
먼저 mysql2라는 모듈이 필요하다. Promise를 적용할 수 있는 mysql 라이브러리이다. npm이나 yarn으로 설치를 하면 된다.
npm i --save mysql2 or yarn add mysql2
Step 1. DB Pool 생성
설치를 마쳤다면 바로 예제로 넘어가자. 먼저 mysql2/promise
를 require한다.
mysql2만 호출하면 기존과 다를바가 없이 Promise 기능을 사용할 수가 없다.
const mysql = require('mysql2/promise');
/* Step 1, create DB Pool */
const pool = mysql.createPool({
host: 'DB_HOST',
user: 'DB_USER',
password: 'DB_PW',
database: 'DBNAME'
});
DB Pool 방식으로 소개하려고 한다. 일단 기본적으로 기존 mysql에서 방법과 유사하다. createPool함수로 Pool을 생성한다.
Step 2. Pool에서 Connection 가져오기
주석 Step 2 이후로 추가된 코드를 먼저 살펴보자.
const mysql = require('mysql2/promise');
/* Step 1, create DB Pool */
const pool = mysql.createPool({
host: 'DB_HOST',
user: 'DB_USER',
password: 'DB_PW',
database: 'DBNAME'
});
/* Step 2. get connection */
const dbTest = async () => {
const connection = await pool.getConnection(async conn => conn);
};
먼저 dbTest 함수에 async가 추가된 것이 보일 것이다. async 함수로 선언되어야 원하는 순서대로 흘러가는 함수를 만들 수 있다. 함수 안에서 pool.getConnection 함수는 connection을 가져오는 함수이다. "mysql2/promise" github에서 코드를 참고해보면 getConnection 함수에는 필수적으로 콜백 함수를 실행시켜 connection을 반환한다. 그래서 그 콜백 함수를 이용해야 한다. getConnection 함수 앞에 await만 선언해서 끝나는 것이 아니고, 그 안의 callback 함수도 async 처리를 해야하는 것이 관건이다. 이렇게 async 함수 내에서 또 async한 작업이 필요하면 꼭 안에 있는 함수에도 선언해야하는 것을 기억하고 넘어가자.
Step 3. 쿼리
const mysql = require('mysql2/promise');
/* Step 1, create DB Pool */
const pool = mysql.createPool({
host: 'DB_HOST',
user: 'DB_USER',
password: 'DB_PW',
database: 'DBNAME'
});
/* Step 2. get connection */
const dbTest = async () => {
try {
const connection = await pool.getConnection(async conn => conn);
try {
/* Step 3. */
const ID = 'HELLO';
const PW = 'WORLD';
const [rows] = await connection.query('INSERT INTO MEMBERS_INFO(ID, PW) VALUES(?, ?)', [ID, PW]);
connection.release();
return rows;
} catch(err) {
console.log('Query Error');
connection.release();
return false;
}
} catch(err) {
console.log('DB Error');
return false;
}
};
connection.query
함수로 쿼리를 실행시키고 결과를 반환 받는데 위와 같이 작성한다. (역시나 await를 써서 해당 결과가 반환 될 때 까지 기다린다.) 배열로 반환 받는 이유는 mysql2/promise 라이브러리에서
쿼리 결과를 반환 받을 때 저렇게 반환 받게 되어있기 때문에 저렇게 작성한다.
그리고 connection을 다 활용했을 경우 connection.release
함수를 호출하여 커넥션을 반환한다.
etc. Transaction
const mysql = require('mysql2/promise');
/* Step 1, create DB Pool */
const pool = mysql.createPool({
host: 'DB_HOST',
user: 'DB_USER',
password: 'DB_PW',
database: 'DBNAME'
});
/* Step 2. get connection */
const dbTest = async () => {
try {
const connection = await pool.getConnection(async conn => conn);
try {
/* Step 3. */
const ID = 'HELLO';
const PW = 'WORLD';
await connection.beginTransaction(); // START TRANSACTION
const [rows] = await connection.query('INSERT INTO MEMBERS_INFO(ID, PW) VALUES(?, ?)', [ID, PW]);
await connection.commit(); // COMMIT
connection.release();
return rows;
} catch(err) {
await connection.rollback(); // ROLLBACK
connection.release();
console.log('Query Error');
return false;
}
} catch(err) {
console.log('DB Error');
return false;
}
};
트랜잭션을 사용할 경우 기존 mysql 라이브러리와 동일하다.
beginTransaction
함수를 호출해주고, 성공시 commit
을 실패 시 rollback
을 사용하면 된다.