MySQL 은 UTF8 구현을 대충 했는지 3 byte 만 처리 가능하고 4 byte 로 인코딩되는 UTF-8 문자를 제대로 지원하지 못하는 문제가 있습니다.


이때문에 UTF-8 로 인코딩을 설정하면 4 byte 도 잘 처리하는 다른 DBMS 와는 달리 utf8mb4 라는 해괴한 인코딩 방식을 사용해야 4byte UTF8 을 지원합니다.


그동안 Confluence 와 JIRA 에서는 MySQL 을 사용할 경우 4 byte UTF-8 을 지원하지 않아서 페이지 내용에 emoji(🍺🍖) 가 있거나 특수 문자가 포함되었을 경우 다음과 같은 에러가 나고 아예 저장이 되지 않는 문제가 있었습니다.

org.springframework.jdbc.UncategorizedSQLException: Hibernate operation: could not update: com.atlassian.confluence.core.BodyContent#38141954; 
uncategorized SQLException for SQL []; SQL state [HY000]; 
error code [1366]; Incorrect string value: '\xF4\x80\x82\x84 z...' for column 'BODY' at row 1; 
nested exception is java.sql.SQLException: Incorrect string value: '\xF4\x80\x82\x84 z...' for column 'BODY' at row 1
Caused by: java.sql.SQLException: Incorrect string value: '\xF4\x80\x82\x84 z...' for column 'BODY' at row 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3536)
CODE



작성중인 문서를 임시 저장하는 기능인 draft 에는 JSON Serialize 시 "\u002f" 와 같이 encoding 을 해서 저장하므로 문제가 없습니다.


드디어 Confluence와 JIRA에서도 MySQL  utf8mb4 인코딩을 지원하므로 새로운 버전을 설치하면 이모지나 특수 문자가 있어도 저장이 가능해 졌습니다.

지원 버전

Confluence 는 7.3 이상 버전, JIRA 는 8.0 이상 버전만 utf8mb4 를 지원합니다.(atlassian 문서 보기)


물론 MySQL 은 5.7.9 이상을 설치해야 합니다.


utf8mb4 로 변경하기


utf8mb4 로 변경하는 절차는 까다롭고 시간이 오래 걸리며 장애로 연결될 수 있으니 꼭 현재 DB 를 백업하고 시작하세요.

변경하는 Database 이름은 confluenceDB 라고 가정합니다.


Database 변경

ALTER DATABASE 구문을 사용해서 Database 의 character set 과 collation 을 utf8mb4 로 변경해 주면 됩니다. 아래는 이름이 confluenceDB 인 Database 를 utf8mb4 로 변경하는 예제입니다.

character set 과 collation 변경

ALTER DATABASE confluenceDB CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
SQL


새로 Database 를 생성할 경우 아래 SQL 을 사용합니다.

utf8mb database 생성

CREATE DATABASE confluence  CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin;
 
CREATE USER 'confluence'@'localhost' IDENTIFIED BY 'secret' PASSWORD EXPIRE NEVER; 
GRANT ALL PRIVILEGES ON confluence.* TO 'confluence'@'localhost';
flush privileges;
SQL


table 변경

다음 SQL 을 실행하면 table 의 chracter set 과 collation 을 변경하는 SQL 이 생성됩니다. 1.sql 이라는 이름의 파일로 저장해 둡니다.

SELECT CONCAT('ALTER TABLE `',  table_name, '` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;')
FROM information_schema.TABLES AS T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` AS C
WHERE C.collation_name = T.table_collation
AND T.table_schema = 'confluenceDB'
AND
(
    CHARACTER_SET_NAME != 'utf8mb4'
    OR
    COLLATION_NAME != 'utf8mb4_bin'
);
SQL


column 변경

다음 쿼리를 실행해서 DATA TYPE 이 varchar 인 컬럼의 character set 과 collation 을 변경하는 SQL 을 2.sql 로 저장해 둡니다.

SELECT CONCAT('ALTER TABLE `', table_name, '` MODIFY `', column_name, '` ', DATA_TYPE, '(', CHARACTER_MAXIMUM_LENGTH, ') CHARACTER SET utf8mb4 COLLATE utf8mb4_bin', (CASE WHEN IS_NULLABLE = 'NO' THEN ' NOT NULL' ELSE '' END), ';')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'confluenceDB'
AND DATA_TYPE = 'varchar'
AND
(
    CHARACTER_SET_NAME != 'utf8mb4'
    OR
    COLLATION_NAME != 'utf8mb4_bin'
) ;
SQL


위 쿼리를 DATA_TYPE != 'varchar' 으로 수정한 후에 다시 실행해서 DATA TYPE 이 varchar 가 아닌 컬럼의 character set 과 collation 을 변경하는 SQL 을 3.sql 로 저장해 둡니다.

SELECT CONCAT('ALTER TABLE `', table_name, '` MODIFY `', column_name, '` ', DATA_TYPE, '(', CHARACTER_MAXIMUM_LENGTH, ') CHARACTER SET utf8mb4 COLLATE utf8mb4_bin', (CASE WHEN IS_NULLABLE = 'NO' THEN ' NOT NULL' ELSE '' END), ';')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'confluenceDB'
AND DATA_TYPE != 'varchar'
AND
(
    CHARACTER_SET_NAME != 'utf8mb4'
    OR
    COLLATION_NAME != 'utf8mb4_bin'
) ;
SQL


이제 커맨드라인에서 다음 명령을 실행해서 DB 를 변경합니다. 

mysql -u confluence -p confluenceDB < 1.sql
mysql -u confluence -p confluenceDB < 2.sql
mysql -u confluence -p confluenceDB < 3.sql
BASH

만약 "ERROR 1832  used in a foreign key constraint" 에러가 나면 SQL 파일의 시작과 끝에 다음 내용을 추가합니다.

SET FOREIGN_KEY_CHECKS=0;
 
-- Insert your other SQL Queries here...
 
SET FOREIGN_KEY_CHECKS=1;
SQL

테스트는 페이지에 아무 emoji(🎁)나 넣어보고 입력이 되는지 확인해 보면 됩니다.

같이 보기

Ref