요약
utf8mb4로 인코딩된 데이터에 접근하고자 할 때,
jdbc:mysql://{db주소}?useUnicode=true&characterEncoding=utf8mb4
대신
jdbc:mysql://{db주소}?useUnicode=true&character_set_server=utf8mb4
쓰세요!
또는,
이미 DB서버의 my.cnf 파일을 character_set_server=utf8mb4로 설정했다면
jdbc:mysql://{db주소}?useUnicode=true
또는
jdbc:mysql://{db주소}?useUnicode=true&characterEncoding=utf8
로 접근하세요!
+ Java 인코딩 - MySQL 인코딩 매핑 테이블
배경
백엔드 -> DB서버에 접속하도록 설정했다.
특히 application.yml 속
spring.datasource.url 을 통해 DB에 어떻게 접근할지 명명하는 부분에서,
characterEncoding=utf8mb4 옵션으로 인코딩 방식을 사용했다
# application.yml (에러)
spring:
datasource:
url: jdbc:mysql://{db연결주소}:3306/{db명}?useUnicode=true&characterEncoding=utf8mb4
에러
하지만 방금과 같이 characterEncoding=utf8mb4로 설정한다면 다음과 같이 에러를 내뱉으며
springboot 백엔드 서버가 실행되지 않는다.
Caused by: com.mysql.cj.exceptions.WrongArgumentException: Unsupported character encoding 'utf8mb4'
응 ?? utf8mb4를 지원하지 않는다고 한다.
하지만,
지난 시간의 수작업을 통해
나는 분명 MySQL 인코딩 방식을 utf8mb4로 변경했다.
MySQL에 접속해봐도 인코딩 방식이 utf8mb4인 것을 확인할 수 있다......
해결
의아한 채로 우선 구글링을 시도했다.
다행히 블로그에 잘 나와있었는데,
https://indienote.tistory.com/664
MySQL - Unsupported character encoding 'utf8mb4'
MySQL 접속에서 (나의경우 MyBatis) 다음과 같은 경우의 에러가 발생하였다. Unsupported character encoding 'utf8mb4' 다음과 같은 연결을 사용하고 있었다. jdbc.url=jdbc:mysql://localhost:3306/dbname?useSSL=false&serverTimez
indienote.tistory.com
이 글에 따르면
characterEncoding=utf8mb4 대신
character_set_server=utf8mb4로 수정해 해결했다고 한다!
나또한 반신반의한 마음으로 적용한 결과,
# application.yml (수정 후)
spring:
datasource:
url: jdbc:mysql://{db연결주소}:3306/{db명}?useUnicode=true&character_set_server=utf8mb4
(application.yml 파일 속 DB url 부분을 수정했다)
어라?
잘 실행되는 모습을 볼 수 있었다...
왜 에러가 발생한 것인가? (관련 용어 정리)
왜 해결된거지? (왜 돌아가지..?)
를 이해하기 위해 좀더 알아보기로 하자.
우선
characterEncoding=utf8mb4 옵션이 뭘 나타내는지 알아보자
1. characterEncoding=utf8mb4 옵션
✔️ 클라이언트 ➔ 서버로 데이터 보낼 때의 인코딩 방식 결정
✔️ Connector/J의 연결 속성 중 하나
Connector/J란?
MySQL 서버와 통신하기 위한 JDBC API & MySQL DevAPI를 구현한 드라이버
https://dev.mysql.com/doc/connector-j/en/
Connector/J의 연결 속성
2. character_set_server=utf8mb4 옵션
✔️ 서버의 인코딩 방식 지정하는 시스템 변수
DB에 어떤 인코딩 방식으로 데이터를 저장할지 명시하는 부분
3. server vs client 인코딩
정리하자면,
characterEncoding은
클라이언트인 Java 어플리케이션 -> DB 서버로 전송할 때의 데이터 인코딩 방식을 의미하고
character_set_server는
DB 서버에서 데이터를 어떻게 저장할것인가? 에 대한 인코딩 방식인 것이다!
(참고) 4. characterEncoding 없을 때는?
✔️ Connector/J 8.0.25 (포함) 이전
characterEncoding 또는 connectionCollation 명시 x
➔ my.cnf 파일 (MySQL 서버 설정 파일)에 정의된 character_set_server 값 사용
✔️ Connector/J 8.0.26 (포함) 이후
characterEncoding 또는 connectionCollation 명시 x
➔ 기본적으로 utf8mb4 문자 집합 사용
왜 에러가 발생한 것인가?
그럼 이제 진짜 왜 에러가 발생한건지 알아보자.
지난 시간의 설정을 통해,
DB의 character_set_server=utf8mb4로 설정했다.
characterEncoding은 자바 어플리케이션에서 DB서버로 보내는 인코딩 양식이라 했다!
그렇다면 Java에서 utf8mb4를 지원하는지를 확인하자!
1. Java에서 지원하는 Charset 확인
// Application.java
import java.nio.charset.Charset;
import java.util.Map;
@EnableJpaAuditing
@SpringBootApplication
public class BusinessCardApplication {
public static void main(String[] args) {
Map<String, Charset> charsets = Charset.availableCharsets(); // 추가
for (String name : charsets.keySet()) { // 추가
System.out.println(name); // 추가
}
SpringApplication.run(BusinessCardApplication.class, args);
}
}
charset 확인 부분을 추가하자!
이어서 application을 실행하니,
Java에서 utf8mb4를 지원하지 않는것을 볼 수 있다!
즉, 나는 client인 Java Application에서 지원하지 않는 인코딩 방식(utf8mb4)를 사용해 에러가 난 것이다!!
해결 방법은 2가지가 있을 것이다.
1. jdbc:mysql://{db주소}?useUnicode=true 로 접근
명시하지 않는 경우,
Connector/J 8.0.26 이전/이후든 서버의 utf8mb4에 맞는 인코딩 방식을 설정할 것이므로 해결될 것이다.
하지만 이참에 Connector/J의 버전도 알아보자!
build.gradle
// build.gradle
dependencies {
// ... 생략
implementation 'com.mysql:mysql-connector-j'
}
헉 버전이 나와있지 않다
이런 경우,
./gradlew dependencies
명령어를 프로젝트 폴더에서 실행하면
의존성 resolve 결과를 알 수 있다고 한다.
(이 작업을 통해 실제 정확한 버전의 라이브러리, 의존성을 다운로드한다고 한다!)
그렇다!
나는 Connector/J 8.0.26 이후 버전이므로,
characterEncoding을 명시하지 않았을 경우 기본적으로 utf8mb4에 맞는 인코딩으로
Java application -> DB 서버로 연결을 시도하는 것이다!
2. jdbc:mysql://{db주소}?useUnicode=true&characterEncoding=utf8 로 접근
이번에는 명시적으로 Java Application -> DB 서버로의 인코딩 방식을 적어주자!
잠깐!
Java - MySQL 간 어떤 인코딩 방식이 매핑되어있는지 어떻게 알지?
공식문서를 보면 된다!
https://dev.mysql.com/doc/connector-j/en/connector-j-reference-charsets.html
MySQL :: MySQL Connector/J Developer Guide :: 6.7 Using Character Sets and Unicode
6.7 Using Character Sets and Unicode All strings sent from the JDBC driver to the server are converted automatically from native Java Unicode form to the connection's character encoding, including all queries sent using Statement.execute(), Statement.exec
dev.mysql.com
이 매핑 테이블을 보면 (마지막 2번째)
utf8mb4에 매핑되는 Java의 인코딩 방식은 UTF-8 이다!
즉,
characterEncoding=utf8
로 Java Application -> DB 서버로 접속하면 되는 것이다!
여담
먼 길 돌아왔다..
인코딩이라고 하면 단순히 DB 저장 인코딩만 생각했는데,
자바 Application -> DB 로의 데이터 전송 인코딩도 있었다니! (신기하다)
또,
의존성 resolve 방식을 찾는 명령어
./gradlew dependencies
를 통해, 라이브러리의 실제 버전을 찾는것도 유용하게 사용할 듯 싶다!
참고
공식문서 - 매핑 테이블 https://dev.mysql.com/doc/connector-j/en/connector-j-reference-charsets.html
공식문서 - characterEncoding https://dev.mysql.com/doc/connector-j/en/connector-j-connp-props-session.html#cj-conn-prop_characterEncoding
같은 에러를 겪은 블로그 - https://indienote.tistory.com/664
'백엔드' 카테고리의 다른 글
[스프링부트] 디스코드 웹훅 (1) - 에러 로그 전송 (logback) (1) | 2025.01.07 |
---|---|
[DB 해킹] MySQL DB 털린 썰 풉니다 (RECOVER_YOUR_DATA) (0) | 2024.12.23 |
[스프링부트] Soft delete 구현 (1) | 2024.12.09 |
[스프링부트] Spring Batch와 적용방법 (3) | 2024.12.09 |
MySQL 한글 (인코딩) 에러 났을 때 해결방법 (0) | 2024.12.09 |