utf8, utf8mb4 인코딩의 이해 (feat. MYSQL 이모지 저장)

프로필 사진mingke

utf8mb4 mysql 이모지 저장

목차

인트로

최근에 아주 바보같은 실수로 문제를 일으켰던 사건이 있었습니다. 유저 관련된 정보를 처리하고 저장하는 로직이 있었는데, 멀쩡하게 잘 되던 API가 500에러를 발생시켰습니다. 알고보니 이모지로 된 닉네임을 저장하던 도중 에러가 발생한 것이었습니다.

MYSQL 8 버젼부터는 CHARACTER SET과 UTF8mb4, COLLATION UTF8mb4_0900_ai_ci 가 기본값이고, 우린 회사는 8버젼을 쓰고있는데 이게 무슨일? 원래는 발생할 수 없는 문제인데

어처구니 없는 실수이기 때문에 해결은 간단하게 했지만, UTF8과 UTF8mb4가 무엇인지 간략하게 보고 어떤 실수였는지 공유하도록 하겠습니다.

UTF8, UTF8mb4 인코딩

UTF8 인코딩은 원래 ASCII 문자 집합을 기반으로 확장된 것으로, 영어와 대부분의 서유럽 언어를 지원합니다.

  • UTF-8에서 영어 알파벳(대문자와 소문자), 숫자, 기본 구두점 등은 ASCII 문자 집합과 동일하게 1바이트로 인코딩됩니다. 예를 들어, 'A'에서 'Z', 'a'에서 'z', '0'에서 '9'와 같은 문자들은 모두 1바이트를 사용합니다.
  • 대부분의 서유럽 언어들, 예를 들면 스페인어, 프랑스어, 독일어 등에서 사용하는 특수 문자는 2바이트로 인코딩됩니다. 이 문자열들은 기본 ASCII 집합에 포함되지 않으며, 추가적인 바이트를 사용하여 표현됩니다.

하지만 UTF8은 각 문자는 최대 3바이트까지만 인코딩 가능합니다. 거의 모든 문자열을 커버 가능하지만, 모든 문자열이 가능한 것은 아닙니다. 저의 사례처럼 이모지😂를 사용한다면? 4바이트까지 커버 가능한 인코딩이 필요합니다.

UTF8mb4 **(UTF-8 Multibyte 4)**인코딩은 위에 3바이트 이상이 필요한 문자열들까지 커버하기 위해 등장했습니다. 모든 유니코드 문자를 지원하며, 특히 4바이트를 요구하는 이모지를 포함한 다양한 문자를 저장할 수 있습니다.

에러가 발생한 이유

  • SQLAlchemy
    • DB_URL 뒤에 charset=utf8라고 지정함
    • 다른 팀원의 코드를 어디선가 복사 붙여넣기를 하는 과정중에 뒤에 mb4를 빼먹음
from sqlalchemy.ext.asyncio import create_async_engine
 
DB_URL="mysql+aiomysql://admin:root@127.0.0.1:3306/admin?charset=utf8"
engine = create_async_engine(DB_URL)
 
  • charset을 설정하지 않아도 됨
"mysql+aiomysql://admin:root@127.0.0.1:3306/admin"

마무리

MYSQL을 사용한다면, 이제는 웬만하면 8버젼대를 사용하기 때문에 이런 실수만 안하면 발생하지 않는 문제였습니다.