MySQL에서 문자셋이 정해지는 세 곳
- 컬럼·테이블: 데이터를 저장하는 문자셋입니다. 예:
utf8mb4,latin1,euckr. - 접속: 클라이언트와 서버가 주고받는 문자셋입니다.
SET NAMES utf8mb4나 드라이버 설정으로 정합니다. - 파일: 가져오기·내보내기 파일을 읽고 쓰는 인코딩입니다. phpMyAdmin 가져오기 화면의 파일 문자셋 항목에서 고릅니다.
증상 1: 한글이 ???로 저장된다
컬럼이나 접속이 latin1 이면 한글을 담을 수 없어 MySQL이 ? 로 바꿔 저장합니다. 오래된 MySQL 5.x의 기본값이 latin1 이라 예전에 만든 테이블에서 자주 생깁니다. 이렇게 저장된 ? 는 원래 글자 정보가 사라진 것이라 어떤 도구로도 되돌릴 수 없습니다. 설정을 고친 뒤 원본 데이터에서 다시 넣어야 합니다.
증상 2: 김민준 같은 글자가 보인다
애플리케이션이 UTF-8 바이트를 latin1 접속으로 latin1 컬럼에 넣은 경우입니다. 같은 방식으로 읽는 애플리케이션 화면은 멀쩡하지만, 올바르게 접속하는 phpMyAdmin과 내보낸 파일에서는 한글이 깨집니다. 이때는 바이트가 그대로 남아 있어 복구할 수 있습니다.
깨진 글자
"1","김민준","서울특별시 종로구 세종대로 209","02-1234-5678"
복구 후
"1","김민준","서울특별시 종로구 세종대로 209","02-1234-5678"
문자셋 확인하기
SHOW VARIABLES LIKE 'character_set%';로 서버와 접속 설정을 봅니다.SHOW CREATE TABLE customers;로 테이블과 컬럼의 문자셋을 봅니다.SELECT name, HEX(name) FROM customers LIMIT 5;로 실제 바이트를 봅니다.utf8mb4컬럼에서김은EAB980입니다.3F는 이미?로 바뀐 글자입니다.
덤프와 내보낸 파일 복구하기
- phpMyAdmin에서 SQL이나 CSV로 내보내거나
mysqldump --default-character-set=utf8mb4를 사용합니다. - 파일을 위 상자에 끌어다 놓습니다. 깨진 부분만 고치고 정상인 한글은 그대로 둡니다.
- 무엇이 바뀌었나요? 에서 바뀐 곳을 확인하고 내려받습니다.
utf8mb4테이블로 가져오면서 파일 문자셋을utf-8로 고릅니다.- 실제 테이블을 바꾸기 전에 복사본으로 먼저 시험해 보세요.
처리는 브라우저 안에서만 이루어져 고객 정보가 담긴 덤프도 외부로 나가지 않습니다. 오래된 시스템에서 받은 EUC-KR 덤프라면 EUC-KR을 UTF-8로 변환도 참고하세요.
원인 고치기
- 새 테이블은
DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci로 만듭니다. - 애플리케이션 접속도
utf8mb4로 맞춥니다. PHP PDO라면 DSN에charset=utf8mb4, JDBC라면characterEncoding=UTF-8을 넣습니다. - UTF-8 바이트가
latin1컬럼에 들어 있다면CONVERT TO로 바로 바꾸지 마세요. 한 번 더 인코딩되어 더 심하게 깨집니다. 먼저MODIFY name VARBINARY(255), 다음에MODIFY name VARCHAR(255) CHARACTER SET utf8mb4로 바이너리 형을 거쳐 바꾸는 것이 안전합니다. utf8이 아니라utf8mb4를 쓰세요. MySQL의utf8은 3바이트까지만 저장해 이모지를 넣으면 오류가 나거나?로 바뀝니다.
자주 묻는 질문
애플리케이션에서는 멀쩡한데 phpMyAdmin에서만 깨지는 이유는?
애플리케이션이 같은 실수를 두 번 하기 때문입니다. UTF-8을 latin1 접속으로 쓰고 같은 방식으로 다시 읽습니다. phpMyAdmin은 올바르게 접속해 실제로 저장된 내용을 보여 줍니다. 이런 현상의 원리는 글자 깨짐이란에서 설명합니다.
이미 ???로 저장된 한글도 복구되나요?
아니요. ? 로 저장될 때 원래 글자 정보가 사라졌습니다. 백업이나 원본 파일에서 다시 가져와야 합니다.
MariaDB도 같나요?
네. MariaDB도 문자셋을 MySQL과 같은 방식으로 다루며 명령도 같습니다.
덤프 파일은 얼마나 커도 되나요?
파일 하나에 100MB까지입니다. 더 큰 데이터베이스는 테이블별로 나눠 내보내세요.