'字符在jdbc中被转换为'

时间:2011-04-05 14:41:29

标签: java mysql jdbc utf-8 character-encoding

我正在尝试从MySql数据库读取UTF-8字符串,我使用它创建:

CREATE DATABASE april
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

我使用以下方式制作感兴趣的表:

DROP TABLE IF EXISTS `article`;
CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `text` longtext NOT NULL,
  `date_created` timestamp DEFAULT NOW(),
  PRIMARY KEY (`id`)
) CHARACTER SET utf8;

如果我在MySql命令行util中 select * from article,我得到:

OIL sands output at Nexen’s Long Lake project dropped in February.

但是,当我这样做时

ResultSet rs = st.executeQuery(QUERY);

long id = -1;
String text = null;
Timestamp date = null;
while (rs.next()) {
    text = rs.getString("text");
    LOGGER.debug("text=" text);
}

我得到的输出是:

text=OIL sands output at Nexen’s Long Lake project dropped in February.

我通过以下方式获取我的连接:

DriverManager.getConnection("jdbc:" + this.dbms + "://" + this.serverHost + ":" + this.serverPort + "/" + this.dbName + "?useUnicode&user=" + this.username + "&password=" + this.password);

我也试过,而不是useUnicode参数:

characterEncoding=UTF-8
and
characterEncoding=utf8

我也尝试过,而不是行text = rs.getString("text")

rs.getBytes("text");
String[] encodings = new String[]{"US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16", "Latin1"};
for (String encoding : encodings) {
    text = new String(temp, encoding);
    LOGGER.debug(encoding + ": " + text);
}
// Which outputted:
US-ASCII: OIL sands output at Nexen��������s Long Lake project dropped in February.
ISO-8859-1: OIL sands output at Nexenââ¬â¢s Long Lake project dropped in February.
UTF-8: OIL sands output at Nexen’s Long Lake project dropped in February.
UTF-16BE: 佉䰠獡湤猠潵瑰畴⁡琠乥硥滃ꋢ芬ꉳ⁌潮朠䱡步⁰牯橥捴⁤牯灰敤⁩渠䙥扲畡特�
UTF-16LE: 䥏⁌慳摮⁳畯灴瑵愠⁴敎數썮겂蓢玢䰠湯⁧慌敫瀠潲敪瑣搠潲灰摥椠敆牢慵祲�
UTF-16: 佉䰠獡湤猠潵瑰畴⁡琠乥硥滃ꋢ芬ꉳ⁌潮朠䱡步⁰牯橥捴⁤牯灰敤⁩渠䙥扲畡特�
Latin1: OIL sands output at Nexenââ¬â¢s Long Lake project dropped in February.

我使用文件中的一些预定义的sql将字符串加载到DB中。该文件是UTF-8编码的。

mysql -u april -p -D april < insert_articles.sql

此文件包含以下行:

 INSERT INTO article (text) value ("OIL sands output at Nexen’s Long Lake project dropped in February.");

当我使用以下内容在我的应用程序中打印出该文件时

BufferedReader reader = new BufferedReader(new FileReader(new File("/home/path/to/file/sql_article_inserts.sql")));
 String str;
 while((str = reader.readLine()) != null) {
     LOGGER.debug("LINE: " + str);
 }

我得到了正确的预期输出:

LINE: INSERT INTO article (text) value ("OIL sands output at Nexen’s Long Lake project dropped in February.");

非常感谢任何帮助。

一些系统细节: 我在linux上运行(Ubuntu)

编辑:
*编辑指定操作系统
*编辑读取sql输入文件的详细输出 *编辑以指定有关数据如何插入数据库的更多信息 *编辑修复代码中的拼写错误,并澄清示例。

4 个答案:

答案 0 :(得分:2)

您是否可能使用不正确的编码读取日志文件? windows-1252,我猜。

UTF-8: OIL sands output at Nexen’s Long Lake project dropped in February.

如果这出现在日志中,请执行日志文件的十六进制转储。如果数据是UTF-8,则您希望序列Nexen’s变为4E 65 78 65 6E E2 80 99 73。如果某个其他应用程序将其读作本机ANSI编码,则会将其解码为Nexen’s

要确认,您还可以转储返回值的各个字符,以查看它们在UTF-16中是否正确:

//untested
for(char ch : text.toCharArray()) {
   System.out.printf("%04x%n", (int) ch);
}

我假设所有数据都在BMP,因此您只需在Unicode charts中查找结果。

答案 1 :(得分:1)

尝试将数据库本身设置为UTF-8。创建数据库时:

CREATE DATABASE mydb
  DEFAULT CHARACTER SET utf8
  DEFAULT COLLATE utf8_general_ci;

另见MySQL reference on connection charsetsMySQL reference on configuring charsets for applications

答案 2 :(得分:0)

JDBC URL中的参数仅定义驱动程序与服务器通信的方式。如果服务器默认不使用UTF8,则这些参数也不会改变它。

连接后尝试执行以下SQL查询吗? (这应该在服务器端将当前连接切换到UTF8):

SET names utf8

答案 3 :(得分:0)

涉及多种字符编码。

  • 运行mysql命令行工具的终端/ cmd窗口。 (腻子?)
  • 你正在运行你的东西的shell(bash)中的环境。 (LC_CTYPE)
  • Mysql internal(在表中使用):您已将其定义为UTF-8
  • JVM内部(始终为UTF16)
  • 记录器使用的编写者使用的字符。默认(系统属性)或可能在日志框架配置中定义。
  • 您阅读日志的终端/ cmd /编辑器。 (putty / bash?)

如果终端设置错误,您可能在mysql中插入了损坏的数据。 (如果您的终端是iso-8859-1,并且您读取的文件是UTF-8,例如)假设linux,mysql应该查看env LC_CTYPE(但我不是100%确定它确实如此。)

JDBCD驱动程序负责将数据库字符编码转换为JVM内部格式(UTF16),因此不应该成为问题。但是您可以使用simpel java程序对其进行测试,该程序会插入硬编码字符串并将其读回。打印原始和收到的字符串 - 它们应该是相同的。但; 如果两者都错, 您的终端字符集定义有问题。

使用像“HejÅÄÖ”这样的字符串来表演戏剧......

另外,编写一个小程序,使用转换为UTF-8的printwriter将相同的字符串打印到文件,并验证用于读取日志的工具是否正确打印该文件。如果没有,则再次怀疑终端设置。

String test = "Test HEJ \u00C5\u00C4\u00D6 ÅÄÖ";
 // here's how to define what character set to use when writing to a fileOutputStream
PrintWriter pw = new PrintWriter("test.txt","UTF8");
pw.println(test);
pw.flush();
pw.close();
System.out.println(test);

输出 - &gt;测试HEJÅÄÖÅÄÖ

文件test.txt的内容应该看起来一样。