Вставка Emoji через MySQL Workbench работает, но не через Java? - PullRequest
0 голосов
/ 09 июня 2018

С помощью MySQL Workbench Queries я смог вставить эмодзи в таблицу , но , только если я сначала установил имена.

SET NAMES utf8mb4; //only need to do this once everytime i start the server
insert into testtable (testfield) values ('?'); //works!

Однако выполнение того же действия в Java приводит к исключению:

java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x96' for column 'testfield' at row 1

Java:

public static void main(String[] args) {
  TestDao t = new TestDao();
  t.setNamesUtf8mb4(); //SET NAMES utf8mb4;
  t.insertTest("?"); //doesn't work :(
}

TestDao

public void setNamesUtf8mb4(){
    try(Connection conn = DBConnection.getConnection()){
        PreparedStatement pst = conn.prepareStatement("SET NAMES utf8mb4;");
           pst.executeUpdate();         
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
public void insertTest(String test){
    try(Connection conn = DBConnection.getConnection()){
        PreparedStatement pst = conn.prepareStatement("insert into testtable (testfield) values (?);");
        pst.setString(1, test);
           pst.executeUpdate(); 
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

DBConnection:

public class DBConnection {
    private static String url = null;
    private static Connection conn = null;
     public static Connection getConnection(){
     try{
       Class.forName("com.mysql.jdbc.Driver");
       url = "jdbc:mysql://localhost:3306/testdb";
       conn = DriverManager.getConnection(url,"root","1234");
     }   catch (Exception e) {
            System.out.println(e);
        } 
     return conn;
     }
}

Моя кодировка и сопоставление для таблицы и базы данных

mysql> SHOW FULL COLUMNS FROM testtable WHERE Field = 'testfield';

+-------+--------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type         | Collation          | Null | Key | Default | Extra | Privileges                      | Comment |
+-------+--------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| testfield | varchar(191) | utf8mb4_unicode_ci | YES  |     | NULL    |       | select,insert,update,references |         |
+-------+--------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name            | Value              |
+--------------------------+--------------------+
| character_set_client     | utf8mb4            |
| character_set_connection | utf8mb4            |
| character_set_database   | utf8mb4            |
| character_set_filesystem | binary             |
| character_set_results    | utf8mb4            |
| character_set_server     | utf8mb4            |
| character_set_system     | utf8               |
| collation_connection     | utf8mb4_unicode_ci |
| collation_database       | utf8mb4_unicode_ci |
| collation_server         | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)

my.ini:

[client]
default-character-set=utf8mb4
[mysql]
no-beep=
default-character-set=utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci
init-connect='SET NAMES utf8mb4'

Я пытался изменить URL-адрес подключения:

url = "jdbc:mysql://localhost:3306/testdb?useUnicode=yes&characterEncoding=UTF-8"; //note: "=utf8mb4" isn't valid here

Все из идей, есть идеи, почему это не работает?Почему он работает только в MySQL Workbench, а не в Java?Это как-то связано с Connector / J?

РЕДАКТИРОВАТЬ

В комментарии предлагается установить имена в том же соединении, что я пробовал, и, похоже, работает.Но разве это не ужасно неэффективно ?Я не хочу выполнять set names перед каждой отдельной вставкой или обновлением ... Конечно, есть лучший способ сделать это?

это работает:

public void insertTest(String test){
    try(Connection conn = DBConnection.getConnection()){
    PreparedStatement pst = conn.prepareStatement("SET NAMES utf8mb4;"); //set names in same connection
               pst.executeUpdate(); 
        pst = conn.prepareStatement("insert into testtable (testfield) values (?);");
        pst.setString(1, test);
           pst.executeUpdate(); 
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

EDIT2

sql версия

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.11    |

pom.xml

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.11</version>
</dependency>

EDIT3

JDK-версия проекта jdk1.8.0_161

И получение шестнадцатеричного теста (?) с помощью:

public String toHex(String arg) {
    return String.format("%040x", new BigInteger(1, arg.getBytes()));
}

дает:

0000000000000000000000000000000000000000000000000000000000000000003f

или получение шестнадцатеричного теста с использованием:

static String stringToHex(String string) {
  StringBuilder buf = new StringBuilder(200);
  for (char ch: string.toCharArray()) {
    if (buf.length() > 0)
      buf.append(' ');
    buf.append(String.format("%04x", (int) ch));
  }
  return buf.toString();
}

производит:

d83d dc96

...