MySQL DB 에 한글 저장시 깨짐현상이 발생하여 트러블슈팅한 과정을 적어보고자 한다.
MySQL Character Set 불일치 문제 해결하기
1. 문제 상황
# 현상
- 한글 데이터 저장 시 깨짐 발생 (예: "안녕하세요" -> "안ë..."")
- 저장된 한글 데이터 조회 시 깨짐
- 개발 환경에서는 정상 동작하나 운영 환경에서 문제 발생
# 증상 확인 방법
- 데이터베이스에서 직접 조회했을 때의 데이터 상태
- 애플리케이션에서 조회했을 때의 데이터 상태
2. 원인 분석
-- 1. Character Set 레벨
Server > Database > Table > Column 순으로 적용
-- 2. Connection 설정 확인
SHOW VARIABLES LIKE '%character%';
SHOW VARIABLES LIKE '%collation%';
-- 3. 설정 불일치 확인
character_set_client = latin1
character_set_connection = latin1
character_set_results = latin1
character_set_database = utf8mb4
2.1 Character Set과 Collation 이해하기
1. Character Set: 문자를 저장하는 인코딩 방식
- utf8mb3: 기본 유니코드 문자 (3바이트)
- utf8mb4: 이모지 포함 모든 유니코드 문자 (4바이트)
- latin1: 서유럽 언어 전용
2. Collation: 문자 정렬과 비교 규칙
- utf8mb4_general_ci: 빠르지만 덜 정확한 정렬
- utf8mb4_unicode_ci: 정확한 유니코드 정렬
- utf8mb4_bin: 바이너리 수준 비교
2.2 문제가 발생하는 과정
1. 클라이언트(PHP/Laravel) -> MySQL 서버 연결 시
- 명시적 설정이 없으면 서버 기본값(latin1) 사용
2. 데이터 저장 과정
[실제 발생하는 과정]
클라이언트(UTF-8 데이터: "안녕")
-> 연결(latin1으로 잘못 해석: "안ë...")
-> DB에 깨진 상태 그대로 저장 ("안ë...")
* DB의 character_set이 utf8mb4여도, 이미 깨진 형태로 전달된 데이터가
그대로 저장됨
3. 데이터 조회 과정
DB(깨진 상태로 저장된 "안ë...")
-> 연결(latin1)
-> 클라이언트에 깨진 상태로 전달
주요 포인트
1. 문제는 데이터가 DB에 저장되기 전, 연결 단계에서 발생
2. DB의 character_set 설정은 이미 깨진 데이터를 받게 되므로 영향을 미치지 못함
3. 따라서 연결 시점의 character_set 설정이 매우 중요
3. 트러블슈팅
3.1 서버 설정 확인
-- 현재 설정 확인
SHOW VARIABLES LIKE '%character%';
SHOW VARIABLES LIKE '%collation%';
-- 데이터베이스 설정 확인
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'your_database';
-- 테이블 설정 확인
SHOW CREATE TABLE your_table;
3.2 문제 해결 단계
-- 1. 서버 설정 변경 (my.cnf)
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
-- 2. 데이터베이스 설정 변경
ALTER DATABASE your_database
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 3. 테이블 설정 변경
ALTER TABLE your_table
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 4. 깨진 데이터 복구
UPDATE your_table
SET column_name = CONVERT(
BINARY(CONVERT(column_name USING latin1))
USING utf8mb4
);
4. Laravel에서의 해결 방법
4.1 설정 파일 수정
// config/database.php
'connections' => [
'mysql' => [
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
...
],
],
4.2 연결된 connection 정보 확인
// 1. 현재 연결의 character set과 collation 확인
$connectionSettings = DB::select("
SELECT @@character_set_client,
@@character_set_connection,
@@character_set_results,
@@collation_connection
");
// 2. 전체 character set 변수 확인
$charsets = DB::select("SHOW VARIABLES LIKE '%character%'");
// 3. 전체 collation 변수 확인
$collations = DB::select("SHOW VARIABLES LIKE '%collation%'");
// 4. 데이터베이스 기본 설정 확인
$dbSettings = DB::select("
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = ?
", [config('database.connections.mysql.database')]);
5. Best Practice
5.1 개발/운영 환경 통일
1. Docker 사용 시
- docker-compose.yml에 MySQL 설정 포함
- custom my.cnf 마운트
2. AWS RDS 사용 시
- Parameter Group 설정
- 개발/운영 동일 Parameter Group 사용
5.2 모니터링 및 유지보수
1. 정기적인 인코딩 설정 확인
- 서버 설정
- 데이터베이스 설정
- 테이블 설정
- 컬럼 설정
2. 로깅 및 모니터링
- 문자셋 변환 오류 로깅
- 이상 문자 발견 시 알림
3. 백업 및 복구 계획
- 인코딩 변경 전 백업
- 복구 절차 문서화
5.3 신규 프로젝트 시작 시 체크리스트
1. 데이터베이스 설정
- Character Set: utf8mb4
- Collation: utf8mb4_unicode_ci
2. 애플리케이션 설정
- Laravel config 설정
'IT > DB' 카테고리의 다른 글
[Mysql] 서비스 다운타임을 최소화할수 있는 테이블 스키마 업데이트 (0) | 2023.10.08 |
---|---|
[DB] 외래키 (foreign key) 사용을 하는게 좋을까? (1) | 2022.11.05 |
[DB] DB 인덱스에 대하여 (1) | 2022.11.01 |