티스토리 뷰
21-2학기 데이터 베이스 프로그래밍 강의를 수강하면서 팀 프로젝트를 진행했다.
Node.js를 사용해 가상 머신에 서버를 구축하고, DB도 설치해서 웹 애플리케이션을 구축했는데,
Node.js를 처음 사용해보면서 겪은 많은 시행착오들과 어려움이 있었다.
그중 하나를 공유해보고자 한다.
우선 우리 팀이 개발한 웹페이지는 아래와 같다. 우리 학교 비교과 프로그램들의 출결을 효율적으로 실행하고 관리할 수 있는 웹앱으로 출석 인증, 설문조사 알림 메일 등 다양한 기능을 지원한다.
내가 맡은 부분은 '출결 관리자'의 메인 화면인데, (1) 로그인한 출결 관리자가 출결 담당하는 강의들을 띄워주고, (2) 각 강의를 클릭했을 때, 유효한 출결 정보가 있다면 그것을, 아니라면 빈 출결 정보 화면을 띄워준다. 마지막으로 (3)'출석 시작'버튼을 클릭하면 적절한 출결 정보를 생성하여 DB에 삽입해준다.
여기서 내가 가장 헤맸던 부분을 바로 '차시'와 관련하여 코드를 구현하는 부분이다. 차시는 강의마다 1개 이상 존재할 수 있는데, 말 그대로 몇 번째 출석 정보인지 나타내는 속성이다. 출석 정보 테이블(attendance_info)에서 기본키를 구성하는 속성이므로 적절한 차시를 가져와서 DB에 삽입해야 정상적으로 INSERT 할 수 있다.
여기서 경우가 두 가지로 나뉜다. 출석 정보를 한 번이라도 생성한 적 있는 강의의 경우 출석 정보 테이블에 해당 정보 인스턴스들이 남아있을 것이고, 그중 MAX(가장 마지막으로 생성한 출석 정보의 차시)를 불러와 +1을 하여 다음 차시를 구성해야 한다. 혹은 한 번도 출석 정보를 생성한 적 없는 강의의 경우 이번에 생성하려는 차시는 1일 것이다.
(TMI: 사실 나는 MySQL MAX 함수가 테이블에 없는 인스턴스에 대해 불러오면 NULL을 반환하여 오류가 날 것이라고 생각해서 나름 경우를 생각하며 코드를 짰는데, 다른 곳에서 실험해보니 없는 인스턴스의 속성에 대해 MAX를 불러오면 에러 없이 '0'을 반환하더라.. 허무해 )
exist 속성은 해당 강의가 한번이라도 출석 정보를 생성한 적 있는지 여부를 담은 bool형 변수이다. (1) exist = True면 한 번이라도 출석 정보를 생성한 적이 있기 때문에 DB에서 MAX + 1 하여 다음 차시를 불러와야 하고, (2) 그 반대는 그냥 + 1 하면 된다.
여기서 Node.js의 Async / Non blocking IO 처리 방식으로 인해 오류가 나는 것은 (1) 번 방식이다.
내가 생각한 코드의 흐름은 A먼저 실행하여 차시를 받아와 다음 차시를 구성하고, B에 A에서 받아온 차시 속성을 담아 INSERT 할 리스트를 구성한다. 다음 C에서 B가 생성한 INSERT 리스트를 실제로 DB에 삽입한다.
하지만 A를 처리하는 동안 Non blocking 방식으로 인해 Node.js는 그 밑에 B, C를 먼저 실행하여 오류가 발생한다.
콘솔 창을 확인해보면 가장 먼저 실행됐어야 한 A파트의 '불러온 차시: 2'가 마지막에 실행됐고, 그 위에 B, C가 먼저 실행되어 차시를 undefined로 DB에 그대로 삽입 시도했음을 알 수 있다. 차시는 기본키이므로 NULL값이 될 수 없고 이는 바로 서버 중단 오류로 이어진다.
그럼 내가 원하는 순서대로 실행되도록 하려면 어떻게 해야할까?
async function GenSQLInsert(){ //SQL Insert문을 동기적으로 실행되도록 하는 함수
//[1] async, await 사용하여 차시 속성 먼저 받아오기
let promise = new Promise((resolve, reject) => {
if(exist){ //(1)DB에서 마지막 차시를 불러와 다음 차시 번호 구성
connection.query(
"SELECT max(degree) as max FROM attendance_info WHERE course_id=?",
[id],
function(err1, rows1){
if(err1)throw err1;
let degree = rows1[0].max + 1;
console.log('불러온 차시: '+degree);
resolve(degree);
});
}
else{//(2) 1차시부터 시작
resolve(1);
}
});
let att_degree = await promise;
console.log(att_degree);
//생략
);
}
GenSQLInsert();
우선 await 키워드는 async로 선언된 함수에서만 동작하기 때문에 async 함수 'GenSQLInser'를 선언해 주고, 내부에 원하는 순서대로 코드를 작성한다. 다만, 가장 선행돼야 하는 [1] DB에서 값을 불러오는 코드는 사진처럼 Promise 안에 작성해 주고 함수 호출 시 await 키워드를 붙여서 해당 코드가 먼저 실행되도록 키워드를 적절히 붙여준다.
await에서 return이 돌아올 때까지 서버가 대기하기 때문에 내가 원하던 흐름으로 A->B->C 코드를 구성할 수 있었다.
'Study > Node.js' 카테고리의 다른 글
[Nest.js] 댓글과 답글 CRUD 구현하는 방법 | 댓글 무한 스크롤 조회 누락 오류 해결 방법 | parentID (0) | 2024.03.27 |
---|---|
[Nest.JS] 무한스크롤을 구현하는 방법 | Cursor Based Pagination 이해하기 | Cursor vs Offset (0) | 2024.02.28 |