С помощью 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