mysql2로 바꿨더니 평점이 갑자기 깨졌다 — DECIMAL이 문자열로 오는 함정
toFixed가 안 먹던 이유
#MySQL #Node #트러블슈팅 #백엔드
커넥션 풀 쓰려고 드라이버를 mysql에서 mysql2로 바꿨다. 대부분 멀쩡했는데, 맛집 별점 화면을 열자마자 콘솔에 이게 터졌다. TypeError: avgRating.toFixed is not a function 분명 숫자여야 하는데 toFixed가 없단다. mysql일 땐 잘 되던 게 mysql2로 바꾸니까 깨진 거다. 범인 찾는 데 시간이 좀 걸렸다. 이 글에선 이 함정을 정리해본다. 증상 맛집마다 별점 평균을 AVG로 구해서 소수점 한 자리로 보여주고 있었다. 프론트는 이랬다. // 평균 별점을 4.5 이런 식으로 표시 span {avgRating.toFixed(1)} /span toFixed는 숫자에만 있는 메서드다. 즉 avgRating이 숫자가 아니라는 얘기였다. 원인: DECIMAL을 문자열로 준다 이유는 황당할 만큼 단순했다. mysql2는 DECIMAL 타입을 기본적으로 문자열로 반환한다 . AVG(star)의 결과가 DECIMAL이라, 4.5라는 숫자가 아니라 "4.5"라는 문자열로 넘어온 거다. 문자열엔 toFixed가 없으니 당연히 깨진다. 구 mysql 드라이버는 이걸 숫자로 줬었는데, mysql2는 정밀도 손실을 막으려고 일부러 문자열로 준다. 큰 숫자에서 자바스크립트 부동소수점 오차 나는 걸 피하려는 의도다. 의도는 좋은데, 모르고 있으면 이렇게 당한다. 해결: 풀 설정 한 줄 + 프론트 이중 방어 풀 만들 때 decimalNumbers: true 옵션을 주면 DECIMAL을 숫자로 받게 할 수 있다. const pool = mysql.createPool({ host: process.env.DB_HOST, // ... // mysql2는 DECIMAL을 기본적으로 문자열로 반환한다. // 숫자로 받아서 프론트의 .toFixed() 같은 게 안 깨지게 함. decimalNumbers: true, }); 그리고 프론트에서도 혹시 모르니 Number()로 한 번 감싸서 이중 방어했다. 백엔드 설정이 어쩌다 바뀌어도 안 깨지게. span {Number(avgRating).toFixed(1)} /span 정리하면 드라이버 바꾸는 건 보통 "import만 바꾸면 되겠지" 싶지만, 이렇게 타입 다루는 방식이 미묘하게 다른 데서 사고가 난다. DECIMAL뿐 아니라 날짜, BIGINT 같은 것도 드라이버마다 처리가 다를 수 있다. 교훈은 두 개다. 하나, 라이브러리 갈아탈 때 "되던 게 왜 갑자기 안 되지" 싶으면 데이터 타입부터 의심하자. 둘, 숫자를 다룰 거면 받는 쪽에서 한 번 더 Number()로 감싸두는 습관이 의외로 많은 사고를 막아준다.