npm install mysql2 --save
npm install dotenv --save
# .env
DATABASE_USER="username"
DATABASE_PASSWORD="password"
DATABASE_NAME="dbname"
DATABASE_HOST="localhost"
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
const conn = mysql.createPool({ //풀 생성
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
port: 3306,
waitForConnections: true, // 풀에 있는 연결이 모두 사용중일 때 대기
connectionLimit: 10, //풀에 넣을 수 있는 최대 연결 수
maxIdle: 10, // 최대 유휴 커넥션, default는 connectionLimit와 동일
idleTimeout: 60000, // 유휴 커넥션 timeout(ms), default는 60000
queueLimit: 0, //대기열에 넣을 수 있는 최대 요청 수
enableKeepAlive: true, //TCP 연결에 keep-alive를 넣을지 결정
keepAliveInitialDelay: 0 //keepAlive 패킷을 처음으로 보낼 때까지의 지연 시간
});
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
const conn = mysql.createPool({ //풀 생성
...
});
const getConnection = async () => { //connection 생성
try {
const connection = await conn.getConnection();
return connection;
} catch (error) {
console.error(`connection error : ${error.message}`);
return null;
}
};
const result = async () => {
const connection = await getConnection();
try {
await connection.beginTransaction(); //트랜잭션 begin
const query = `SELECT * FROM USER WHERE name = ? AND email = ?`;
const data = ['potato','potato@potato.com'];
const result = await connection.query(query, data);
await connection.commit(); //commit
return result;
} catch (err) {
console.log("rollback connection");
await connection.rollback(); // rollback
console.error("db error : ", err);
} finally {
console.log("release connection");
connection.release(); //connection release
}
}
... 이렇게 하면 기본은 끝나지만
Java, SpringBoot 를 사용했던 개발자라면 어딘가 불편할 것이다.
Spring 진영에는 AOP활용으로 @Transactional
을 통해 트랜잭션 로직과 비즈니스 로직을 분리 할 수 있었지만
nodejs에서는 특정 ORM을 사용하지 않는 이상 트랜잭션 로직과 비즈니스 로직을 분리하는 방법을 찾을 수 없었다. (TypeORM을 사용하면 분리가 가능하다고 한다.)
(그냥 내가 못 찾은 거일 수도 있다만...방법을 알고 계신다면 제보 부탁드립니다.)
그래서 최대한 분리를 해본 결과 아래와 같은 결과가 나왔다.
dbConfig.js
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
const conn = mysql.createPool({ //풀 생성
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
port: 3306,
...
});
const getConnection = async () => {
try {
const connection = await conn.getConnection();
return connection;
} catch (error) {
console.error(`connection error : ${error.message}`);
return null;
}
};
exports.transaction = async (logic, req) => {
const connection = await getConnection();
try {
await connection.beginTransaction();
const result = await logic(connection, req);
await connection.commit();
return result;
} catch (err) {
console.log("rollback connection");
await connection.rollback();
console.error("db error : ", err);
} finally {
console.log("release connection");
connection.release();
}
}
repository.js
exports.findById = async (conn, id) => {
try {
const query = `SELECT * FROM users where id = ?`;
const [result] = await conn.query(query, id);
return result[0];
} catch (err) {
console.error("db err : ", err);
}
}
service.js
const repository = require('../repository/repository');
exports.getUserData = async (conn, userId) => {
return await repository.findById(conn, userId);
}
controller.js
const service = require('../service/service');
const { tx } = require('../db/dbConfig');
exports.getServiceBillings = async (req, res) => {
const result = await tx(repository.getUserData, 1);
return res.status(200).send(result);
}
최대한 분리를 해본 결과 계층간 분리는 되었으나 파라미터로 connection을 넘겨줘야했다.
다른 방법을 계속 찾아봐야 할 것 같다.