[java] java.sql.SQLException : 잘못된 문자열 값 : ‘\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F…’

다음 문자열 값이 있습니다. “walmart obama ??”

MySQL과 Java를 사용하고 있습니다.

다음 예외가 발생합니다.`java.sql.SQLException : 잘못된 문자열 값 : ‘\ xF0 \ x9F \ x91 \ xBD \ xF0 \ x9F …’

삽입하려는 변수는 다음과 같습니다.

var1 varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL`

“walmart obama ??”를 삽입하려는 Java 코드가 준비된 상태입니다. 그래서 나는 setString()방법을 사용하고 있습니다.

문제는 ?? 값의 인코딩 인 것 같습니다. 이 문제를 어떻게 해결할 수 있습니까? 이전에는 Derby SQL을 사용했고 ?? 값은 2 sqaures로 끝났습니다 (나는 이것이 널 문자의 표현이라고 생각합니다)

모든 도움에 감사드립니다!



답변

당신이 가진 것은 EXTRATERRESTRIAL ALIEN (U+1F47D)하고 BROKEN HEART (U+1F494)있는 기본 다국어 평면에 있지 않습니다. 그들은 자바에서 하나의 문자로 표현 될 수도 없습니다 "??".length() == 4. 확실히 null 문자가 아니며 지원하는 글꼴을 사용하지 않으면 사각형이 표시됩니다.

MySQL utf8은 기본 다국어 평면 만 지원하며 utf8mb4대신 다음 을 사용해야 합니다 .

보충 문자의 경우 utf8은 문자를 전혀 저장할 수 없지만 utf8mb4는이를 저장하는 데 4 바이트가 필요합니다. utf8은 문자를 전혀 저장할 수 없기 때문에 utf8 열에 보충 문자가 없으며 이전 버전의 MySQL에서 utf8 데이터를 업그레이드 할 때 문자 변환이나 데이터 손실에 대해 걱정할 필요가 없습니다.

따라서 이러한 문자를 지원하려면 MySQL이 5.5 이상이어야하며 utf8mb4모든 곳 에서 사용해야 합니다. 연결 인코딩은이어야 utf8mb4하고 문자 세트는이어야 utf8mb4하며 조합은이어야 utf8mb4합니다. Java의 경우 여전히 "utf-8"이지만 MySQL에는 구별이 필요합니다.

어떤 드라이버를 사용하고 있는지 모르겠지만 드라이버에 구애받지 않는 연결 문자 집합을 설정하는 방법은 쿼리를 보내는 것입니다.

SET NAMES 'utf8mb4'

연결 직후.

Connector / J에 대한 내용도 참조하십시오 .

14.14 : Connector / J에서 4 바이트 UTF8, utf8mb4를 어떻게 사용할 수 있습니까?

Connector / J에서 4 바이트 UTF8을 사용하려면 character_set_server = utf8mb4로 MySQL 서버를 구성합니다. Connector / J는 연결 문자열에 characterEncoding이 설정 되지 않은 한 해당 설정을 사용
합니다 . 이것은 문자 집합의 자동 감지와 동일합니다.

열과 데이터베이스도 조정하십시오.

var1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL

다시 말하지만, MySQL 버전은 utf8mb4 지원을 위해 비교적 최신 버전이어야합니다.


답변

대체로 4 바이트가 필요한 기호를 저장하려면 characher-set 및 collation을 업데이트해야합니다 utf8mb4.

  1. 데이터베이스 테이블 / 열 :
    alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. 데이터베이스 서버 연결 ( 참조 )

# 2의 개발 환경에서 서버를 시작할 때 명령 줄에 매개 변수를 설정하는 것을 선호합니다.
mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


BTW에주의를 기울 커넥터 / J 행동SET NAMES 'utf8mb4':

커넥터 / J를 사용하여 쿼리 세트 이름을 발행하지 마십시오. 드라이버는 문자 세트가 변경되었음을 감지하지 않고 초기 연결 설정 중에 감지 된 문자 세트를 계속 사용합니다.

characterEncoding연결된 서버 인코딩을 재정의하므로 연결 URL에서 매개 변수를 설정하지 마십시오 .

클라이언트 측에서 자동으로 감지 된 인코딩을 재정의하려면 서버에 연결하는 데 사용되는 URL에서 characterEncoding 속성을 사용합니다.


답변

이상하게, 나는 제거하기 것을 발견 &characterEncoding=UTF-8으로부터 것은 JDBC url유사한 문제로 나를 위해 트릭을했다.

내 속성에 따라

jdbc_url=jdbc:mysql://localhost:3306/dbName?useUnicode=true

나는 이것이 @Esailija가 위에서 말한 것을 지원한다고 생각합니다. 즉, 실제로 5.5 인 내 MySQL은 UTF-8 인코딩의 가장 좋아하는 맛을 파악하고 있습니다.

(참고, 나는 또한 InputStream내가 읽고 UTF-8있는 자바 코드를 지정하고 있는데, 아마 아프지 않을 것입니다) …


답변

내 문제를 어떻게 해결했는지.

나는 가지고 있었다

?useUnicode=true&amp;characterEncoding=UTF-8

내 최대 절전 모드 jdbc 연결 URL에서 문자열 데이터 유형을 이전에 varchar였던 데이터베이스의 longtext로 변경했습니다.


답변

useUnicode=true&amp;characterEncoding=UTF-8jdbc URL에 줄 을 추가하십시오 .

귀하의 경우 데이터는 UTF-8인코딩을 사용하여 전송되지 않습니다 .


답변

나는 같은 문제에 직면하고 각 열에 대해 Collationutf8_general_ci 로 설정하여 해결했습니다 .


답변

MySQL은 이것이 유효한 UTF8 텍스트라고 믿지 않는다고 생각합니다. 동일한 열 정의 (mysql 클라이언트 연결도 UTF8)로 테스트 테이블에 삽입을 시도했지만 삽입했지만 MySQL CLI 클라이언트와 JDBC로 검색 한 데이터는 값을 올바르게 검색하지 못했습니다. UTF8이 올바르게 작동하는지 확인하기 위해 오바마에 “o”대신 “ö”를 삽입했습니다.

johan@maiden:~$ mysql -vvv test < insert.sql
--------------
insert into utf8_test values(_utf8 "walmart öbama ??")
--------------

Query OK, 1 row affected, 1 warning (0.12 sec)

johan@maiden:~$ file insert.sql
insert.sql: UTF-8 Unicode text

테스트 할 작은 Java 애플리케이션 :

package test.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class Test
{

    public static void main(String[] args)
    {
        System.out.println("test string=" + "walmart öbama ??");
        String url = "jdbc:mysql://hostname/test?useUnicode=true&characterEncoding=UTF-8";
        try
        {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            Connection c = DriverManager.getConnection(url, "username", "password");
            PreparedStatement p = c.prepareStatement("select * from utf8_test");
            p.execute();
            ResultSet rs = p.getResultSet();
            while (!rs.isLast())
            {
                rs.next();
                String retrieved = rs.getString(1);
                System.out.println("retrieved=\"" + retrieved + "\"");

            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

산출:

johan@appel:~/workspaces/java/javatest/bin$ java test.sql.Test
test string=walmart öbama ??
retrieved="walmart öbama "

또한 JDBC 연결로 동일한 삽입을 시도했으며 동일한 예외가 발생했습니다. 나는 이것이 MySQL 버그라고 생각합니다. 이미 그런 상황에 대한 버그 리포트가 있을지도 ..