티스토리 뷰

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 코드를 구성할 수 있었다.

 

 

 

async와 await

 

ko.javascript.info

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함