mysql github 공식docs
mysql2 github docs
데이터베이스 통신은 비동기로 진행되는데, mysql 모듈에서는 비동기를 콜백으로 처리해 주어야 한다.
하지만, mysql2에서는 async, await 등 promise를 지원하기 때문에 비동기 처리에 더 유용하다.
위의 차이를 정리할 필요가 있다.
const db = mysql.createConnection({
host: process.env.DATA_HOST,
user: process.env.DATA_USERNAME,
database: 'nodemysql',
password: process.env.DATA_PASSWORD,
});
db.connect((err) => {
if (err) {
throw console.log(err);
}
console.log('connected');
});
app.get('/addpost2', (req, res, next) => {
let post = { title: 'post two', body: 'this is post two' };
let sql = 'insert into posts set ?';
db.query(sql, post, (err, result) => {
if (err) throw err;
res.send('post two created');
});
});
app.get('/getpost', (req, res, next) => {
let sql = 'select * from posts';
db.query(sql, (err, result) => {
if (err) throw err;
console.log(result);
res.send('posts fetcehd');
});
});
post: (userId, orders, totalPrice, callback) => {
let sql = `INSERT INTO orders VALUES (default, ${userId}, ${totalPrice}, default)`;
db.query(sql, (err, result) => {
let insertId = result.insertId;
let sql2 = `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`;
let orderArr = orders.map((v) => {
return [insertId, v.itemId, v.quantity];
});
db.query(sql2, [orderArr], (err, result) => {
callback(err, result);
});
});
},
위의 코드는 하나의 요청에 두가지의 데이터베이스 처리를 한다.
1. orders 테이블 row insert
2. orders 테이블의 id를 외래키로하는 order_items 테이블의 row insert
이러한 하나의 유닛으로 처리되어야 하는 경우 트랜잭션의 안정성 처리를 해주지 않으면 다음과 같은 문제가 발생하게 된다.
예를 들면
orders 테이블의 row는 정상적으로 생성되었으나, orders의 데이터가 비정상적인 경우 order_items 테이블의 row는 생성되지 않을 수 있다.
이런 경우 두 테이블간의 일관성이 깨지게 된다.
위의 이미지를 보면 orders 테이블의 id 72인 새로운 row는 생성되었지만, order_items에서는 order_id가 72인 새로운 row가 추가되지 않음
을 확인 할 수 있다.
때문에
하나의 트랜잭션(transaction)의 안전성을 보장하기 위해 트렌잭션의 성공 여부에 대해 COMMIT과 ROLLBACK으로 선언해 주어야 한다.
즉, 하나라도 실패를 하게 되면 트랜잭션도 실패이고, 모든 작업이 성공적이면 트랜잭션 또한 성공이다.
post: (userId, orders, totalPrice, callback) => {
db.beginTransaction((err) => {
if (err) return callback(err, result);
let sql = `INSERT INTO orders VALUES (default, ${userId}, ${totalPrice}, default)`;
db.query(sql, (err, result) => {
if (err) {
db.rollback();
return callback(err, result);
}
let insertId = result.insertId;
let sql2 = `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`;
let orderArr = orders.map((v) => {
return [insertId, v.itemId, v.quantity];
});
db.query(sql2, [orderArr], (err, result) => {
if (err) {
db.rollback();
return callback(err, result);
}
db.commit();
return callback(err, result);
});
});
});
},
mysql 모듈의 beginTransaction 메소드를 사용하여 어느 하나의 단계에서라도 실패하면 db.rollback()
을 해주고, 가장 마지막 작업까지 성공적으로 진행된다면 그때 db.commit()
을 해준다.
이렇게 해준다면 설령 orders 테이블의 새로운 row가 추가될 조건은 만족되더라도 이후의 order_items의 새로운 row를 추가하는 과정에서 실패하게 되고, 모든 것이 rollback되므로 데이터베이스의 안정성, 일관성을 유지할 수 있게 된다.